Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:NVIDIA NeMo Curator PreviewStage

From Leeroopedia
Revision as of 13:21, 16 February 2026 by Admin (talk | contribs) (Auto-imported from implementations/NVIDIA_NeMo_Curator_PreviewStage.md)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Knowledge Sources
Domains Video Processing, Media Encoding, Preview Generation
Last Updated 2026-02-14 00:00 GMT

Overview

PreviewStage generates animated WebP preview images from video clip windows using FFmpeg, producing lightweight thumbnails for quick visual inspection of curated video content.

Description

PreviewStage extends ProcessingStage[VideoTask, VideoTask] as a Python dataclass. It iterates over each clip and its windows in a VideoTask, writing the MP4 bytes of each window to a temporary file, invoking FFmpeg with the libwebp encoder to produce a lossy animated WebP at a configurable target FPS and height, and reading the resulting bytes back into window.webp_bytes.

The stage supports configurable compression parameters: compression_level (0-6, where 0 is lossless and 6 is most lossy) and quality (0-100, where 100 is highest quality). It allocates CPU resources via Resources(cpus=num_cpus_per_worker) and uses the allocated CPU count as the FFmpeg thread count.

The stage emits warnings when the source video's framerate or resolution is below the target preview settings, indicating that preview quality may be degraded. FFmpeg errors are caught and logged without raising exceptions, allowing the pipeline to continue processing other windows.

Usage

Use PreviewStage in video curation pipelines when you need lightweight animated preview thumbnails of video clips. Place it after clip extraction stages to generate preview images that can be used for visual inspection, quality review, or content browsing without requiring full video playback.

Code Reference

Source Location

  • Repository: NeMo-Curator
  • File: nemo_curator/stages/video/preview/preview.py
  • Lines: 1-116

Signature

@dataclass
class PreviewStage(ProcessingStage[VideoTask, VideoTask]):
    target_fps: float = 1.0
    target_height: int = 240
    verbose: bool = False
    num_cpus_per_worker: float = 4.0
    compression_level: int = 6
    quality: int = 50

    def __post_init__(self) -> None: ...
    def inputs(self) -> tuple[list[str], list[str]]: ...
    def outputs(self) -> tuple[list[str], list[str]]: ...
    def process(self, task: VideoTask) -> VideoTask: ...
    def _generate_preview(self, window: _Window) -> None: ...

Import

from nemo_curator.stages.video.preview.preview import PreviewStage

I/O Contract

Inputs

Name Type Required Description
target_fps float No Target frames per second for the preview animation (default: 1.0)
target_height int No Target height in pixels for the preview, width is scaled proportionally (default: 240)
verbose bool No Enable verbose output (default: False)
num_cpus_per_worker float No Number of CPUs allocated per worker, also used as FFmpeg thread count (default: 4.0)
compression_level int No WebP compression level from 0 (lossless) to 6 (most lossy) (default: 6)
quality int No WebP quality from 0 (worst) to 100 (best) (default: 50)
task VideoTask Yes Video task containing clips with windows that have MP4 bytes to convert

Outputs

Name Type Description
result VideoTask The same video task with webp_bytes populated on each processed window

Key Implementation Details

Processing Loop

The process() method iterates over all clips and their windows, generating a preview for each:

def process(self, task: VideoTask) -> VideoTask:
    video: Video = task.data
    if video.metadata.framerate < self.target_fps:
        logger.warning(f"Video {video.input_video} has framerate {video.metadata.framerate} < {self.target_fps}, preview generation quality will be degraded.")
    if video.metadata.height < self.target_height:
        logger.warning(f"Video {video.input_video} has height {video.metadata.height} < {self.target_height}, preview generation quality will be degraded.")
    for clip in video.clips:
        for window in clip.windows:
            self._generate_preview(window)
    return task

FFmpeg Command Construction

The _generate_preview method constructs an FFmpeg command with the following key parameters:

command = [
    "ffmpeg",
    "-threads", str(int(self.resources.cpus)),
    "-y",
    "-i", input_mp4.as_posix(),
    "-loglevel", "error",
    "-vf", f"fps={self.target_fps},scale=-1:{self.target_height}",
    "-c:v", "libwebp",
    "-lossless", str(0),
    "-compression_level", str(self.compression_level),
    "-q:v", str(self.quality),
    "-loop", "0",
    output_webp.as_posix(),
]

Key FFmpeg settings:

  • -vf applies a filter chain: first resamples to the target FPS, then scales height while preserving aspect ratio (-1 for width)
  • -c:v libwebp uses the WebP video codec for animated output
  • -lossless 0 forces lossy encoding
  • -loop 0 creates an infinitely looping animation

Temporary File Management

The stage uses make_pipeline_temporary_dir to create a temporary directory for each preview generation operation. Input MP4 bytes are written to disk, FFmpeg processes them, and the output WebP bytes are read back, all within a context manager that handles cleanup:

with make_pipeline_temporary_dir(sub_dir="preview") as tmp_dir:
    input_mp4 = pathlib.Path(tmp_dir, "input.mp4")
    input_mp4.write_bytes(window.mp4_bytes)
    output_webp = pathlib.Path(tmp_dir, "output.webp")
    # ... run FFmpeg ...
    window.webp_bytes = output_webp.read_bytes()

Error Handling

FFmpeg failures are caught and logged without raising exceptions, allowing the pipeline to continue processing remaining windows:

try:
    output = subprocess.check_output(command, stderr=subprocess.STDOUT)
    if output:
        logger.warning(f"FFmpeg output: {output.decode('utf-8')}")
except subprocess.CalledProcessError as e:
    logger.error(f"FFmpeg command failed with return code {e.returncode}")
    if e.output:
        logger.warning(f"FFmpeg output: {e.output.decode('utf-8')}")
    return

Usage Examples

Basic Usage

from nemo_curator.stages.video.preview.preview import PreviewStage

preview_stage = PreviewStage(
    target_fps=1.0,
    target_height=240,
    quality=50,
)

High-Quality Previews

from nemo_curator.stages.video.preview.preview import PreviewStage

preview_stage = PreviewStage(
    target_fps=2.0,
    target_height=480,
    compression_level=3,
    quality=80,
    num_cpus_per_worker=8.0,
)

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment