Nodes/comfyui-AGSoft/🎬AGSoft Get Video Components
ComfyUI Node

🎬AGSoft Get Video Components

The video node that hands you the numbers, not just the frames

By Art-xmaster·Created about a year ago·Updated 2 days ago· 33
🎬AGSoft Get Video Components
  • video
  • images
  • audio
  • width
  • height
  • total_frames
  • duration_seconds
  • fps
  • bit_depth
  • color_space

Core ComfyUI already ships a Get Video Components node. It walks a VIDEO object and drops out frames, audio, fps, bit depth and color space - everything you need to look at a clip and nothing you need to do math on one. No width. No height. No frame count. No duration. That's the hole this node fills: same demux, plus the four numbers people keep reaching for Get Image Size and a counter to reconstruct.

You reach for it the moment a video stops being a black box in your graph. The standard community recipe for anything per-frame is literally "Get Video Components → Batch to List → RMBG → List to Batch → Make Video" - demux, mangle every frame, reassemble. Once you're reassembling, you need fps to encode at the right speed and total_frames/duration_seconds to know whether you got back the same clip. Same story inside this pack's own video family: duration_seconds and fps feed the time effects, split and stitch nodes, images feeds anything IMAGE, audio feeds the audio nodes.

How it works

A VIDEO is a lazy handle, not a pile of pixels, and this node is where the decode actually happens. It calls get_components() in one pass: PyAV opens the container and decodes every frame into a single float32 IMAGE batch, with the audio waveform and the stream's frame rate (a Fraction) alongside. The extras cost nothing after that - width, height and total_frames are read straight off the decoded tensor's shape, and duration_seconds is total_frames / fps.

Worth knowing why that's stated so plainly in the tooltip: geometry is taken from the decoded frames, after any crop or rotation the source VIDEO already applied. So if an upstream node trimmed or rotated your clip, you get the numbers for what's actually flowing down the wire, not for the file on disk.

It's also defensive by design. get_components() first, then the legacy get_pixels(), then a dict, then a bare tensor. A 5-dimensional [B,F,H,W,C] batch gets flattened, the tensor is detached and cast to float32, and anything whose max is above 1.5 is assumed to be 0..255 and divided down. bit_depth and color_space fall back to 8 and sRGB, and an empty video returns zeros instead of raising.

Inputs and outputs

One input: video (VIDEO). Native Load Video, AGSoft Load Video, or a model's video output all work.

The outputs that matter:

  • images - every frame as an (N, H, W, 3) float32 batch in 0..1.
  • audio - an AUDIO object, or None if the file has no decodable audio stream.
  • duration_seconds - total_frames / fps, exact for constant-frame-rate clips.
  • total_frames, fps, width, height - INT/INT/FLOAT/INT, the numbers you wire in instead of hand-counting. Plus bit_depth and color_space read off the source stream.

Installing it

ComfyUI Manager → search comfyui-AGSoft → install → restart. Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/Art-xmaster/comfyui-AGSoft.git

Dependencies come from the pack's requirements.txt / pyproject.toml: numpy, opencv-python, and translators (the last is for the pack's Translate nodes, not this one). No model files to download. The pack is 100-plus nodes loaded dynamically, so if a module fails to import you'll see a bilingual Import error in module '...' line in the console and everything else still loads - check this node is actually present before assuming the install failed.

Where people get burned

RAM, not VRAM. images is the entire clip decoded at float32, held in system memory, and there is no partial mode. A 10-second 1080p clip at 24fps is roughly 6 GB - 1920×1080×3×4 bytes is about 25 MB per frame. If you only want the duration, you're still paying for the full decode - on a long 4K file that's an absurd price for one number. Get the metadata at load time where you can.

duration_seconds is arithmetic, not a probe. total_frames / fps is exactly right for CFR video and quietly wrong for variable-frame-rate captures - screen recordings, some webm, anything that dropped frames. If it disagrees with mpv, that's why. And if fps comes back as 0 (broken or audio-only container), duration is 0.0 rather than an error, which is polite right up until something downstream divides by it.

audio is None on silent clips. Wire that None into an AUDIO input and you can blow up a run that otherwise looked fine. Leave the wire off until you know the source has a track.

Don't audit HDR with bit_depth/color_space. For videos built in-memory from tensors, core reports the encoding defaults (8, sRGB) because there's no file stream to inspect. Those outputs are meaningful for file-backed videos only.

Alpha is dropped. The VIDEO object can carry a separate alpha channel; this node's images output is RGB. Demuxing here won't get you transparency.

CategoryAGSoft/Video

Inputs (1)

NameTypeDefaultDescription
videoVIDEOVIDEO object to extract components from. Accepts output of AGSoft Load Video, native Load Video or any object with get_components()/get_pixels(). --- Объект VIDEO для разбора. Принимает выход AGSoft Load Video, нативного Load Video или любого объекта с get_components()/get_pixels().

Outputs (9)

NameTypeDescription
imagesIMAGEAll video frames as a (N, H, W, 3) IMAGE batch, float32, range 0..1. --- Все кадры видео как батч IMAGE (N, H, W, 3), float32, диапазон 0..1.
audioAUDIOAudio track as an AUDIO object (waveform + sample_rate), or None if the video has no decodable audio stream. --- Звуковая дорожка как объект AUDIO (waveform + sample_rate), либо None, если в видео нет декодируемой аудиодорожки.
widthINTFrame width in pixels — taken from the decoded frame tensor (after any source-applied crop/rotation). 0 if the video is empty. --- Ширина кадра в пикселях — из декодированного тензора кадров (с учётом crop/rotation от источника). 0, если видео пустое.
heightINTFrame height in pixels — taken from the decoded frame tensor (after any source-applied crop/rotation). 0 if the video is empty. --- Высота кадра в пикселях — из декодированного тензора кадров (с учётом crop/rotation от источника). 0, если видео пустое.
total_framesINTTotal number of frames extracted. Equals images.shape[0]. 0 if the video is empty. --- Общее число извлечённых кадров. Равно images.shape[0]. 0, если видео пустое.
duration_secondsFLOATExact clip duration in seconds (total_frames / fps). 0.0 if the video is empty or fps is invalid. --- Точная длительность клипа в секундах (total_frames / fps). 0.0, если видео пустое или fps некорректен.
fpsFLOATFrame rate in frames per second (float). --- Частота кадров (float).
bit_depthINTBit depth per color component of the source video stream (int). Falls back to 8 when the stream metadata is missing. --- Битность на цветовую компоненту исходного видеопотока (int). Фоллбэк на 8, если метаданные потока отсутствуют.
color_spaceSTRINGColor space / transfer of the decoded frames: 'sRGB', 'HDR' or 'HDR PQ'. Falls back to 'sRGB' for unknown transfer. --- Цветовое пространство / transfer декодированных кадров: 'sRGB', 'HDR' или 'HDR PQ'. Фоллбэк на 'sRGB' для неизвестного transfer.