flashdreams-postprocessing
FlashDreams-Video-Post-Processing-Prozessoren, -Sitzungen, -Voreinstellungen und Runner-Stream-Verdrahtung hinzufügen oder ändern. Verwenden Sie dies bei der Implementierung einer neuen VideoPostProcessorConfig /…
npx skills add https://github.com/nvidia/flashdreams --skill flashdreams-postprocessingFlashDreams Post-Processing
Use this skill when adding a video post-processor or changing the runner
post-processing stream. The reference implementation is
integrations/flashvsr/flashvsr/postprocess.py.
Mental Model
A post-processor is usually three classes, not one class inheriting everything:
VideoPostProcessorConfig: serializable config and CLI surface. It sets_targetto the processor factory and declares fields,output_spec(),requires_all_ranks(), andvalidate_execution().VideoPostProcessor: lightweight factory created from config. Its job isstart(spec) -> VideoPostProcessorSession.VideoPostProcessorSession: mutable per-stream runtime. It owns buffers, caches, lazy model instances, counters, andprocess()/flush().
Keep stream state in the session. Do not store per-rollout mutable state on the config or processor factory.
Implementation Steps
-
Pick a home:
- Generic reusable post-processing belongs under
flashdreams/flashdreams/infra/postprocess/. - Model-specific processors belong in their integration, for example
integrations/<name>/<pkg>/postprocess.py.
- Generic reusable post-processing belongs under
-
Define a config subclass:
@dataclass(kw_only=True) class MyPostProcessorConfig(VideoPostProcessorConfig): _target: type["MyPostProcessor"] = field( default_factory=lambda: MyPostProcessor ) scale: int = 2 def output_spec(self, input_spec: VideoSpec) -> VideoSpec: return VideoSpec( height=input_spec.height * self.scale, width=input_spec.width * self.scale, fps=input_spec.fps, channels=input_spec.channels, )Override:
output_spec()when spatial size, channels, or timing changes.requires_all_ranks()when the processor must run on nonzero ranks undertorchrun.validate_execution()to reject unsupported distributed or shape modes early.
-
Define the processor factory:
class MyPostProcessor(VideoPostProcessor[MyPostProcessorConfig]): def start(self, spec: VideoSpec) -> VideoPostProcessorSession: return _MyPostProcessorSession(self.config, spec) -
Define the session:
class _MyPostProcessorSession(VideoPostProcessorSession): def __init__(self, config: MyPostProcessorConfig, spec: VideoSpec) -> None: self._config = config self._spec = spec self._buffer: Tensor | None = None def process(self, chunk: VideoChunk) -> list[VideoChunk]: ... def flush(self) -> list[VideoChunk]: ...process()is synchronous but may return[]: that means it consumed the input chunk and is buffering frames until a later chunk orflush()can complete an output window. -
Handle layouts at the boundary:
- Accept
VideoChunk.tensorinchunk.layout. - Use
to_bvtchw()only as a generic boundary helper. - Convert once into the processor's native layout, make it contiguous if the model kernels require that, and keep internal buffers in that native layout.
- Document any forced
.contiguous()because it can copy.
- Accept
-
Return
VideoChunks:- Preserve
[-1, 1]value range unless the API is intentionally changed. - Set the correct
layout. - Carry metadata only if it helps downstream processors or provenance.
- Preserve
-
Register presets when users should select it from CLI:
[project.entry-points."flashdreams.postprocess_presets"] "my-postprocessor-v1" = "my_pkg.postprocess:POSTPROCESS_PRESET_MY_V1"The exported object must be a
VideoPostProcessorConfig, for example:POSTPROCESS_PRESET_MY_V1 = MyPostProcessorConfig(...)Users select it with
--postprocess.preset my-postprocessor-v1.
Runner Interaction
Runners create a VideoPostprocessStream through
create_runner_postprocess_stream(). The stream:
- creates one chain session for whole-stream processing, or one session per
view when
postprocess_per_view=True; - calls
session.process(VideoChunk(...))for each AR output; - turns
[]into a zero-frame tensor soprocess()remains tensor-only; - skips collecting zero-time tensors in
_append_if_nonempty(); - calls
flush()once at end-of-stream and appends any tail output.
Use postprocess_output_layout to describe the runner's decoded output layout.
Use postprocess_per_view=True for bvtchw outputs when each camera/view needs
an independent processor session.
Tests
Add CPU-safe tests unless the behavior genuinely requires a GPU:
- Config/preset discovery:
flashdreams/tests/test_postprocess_presets.py. - Stream contract and buffering:
flashdreams/tests/test_postprocess_stream.py. - Processor-specific CPU fakes:
integrations/<name>/tests/test_postprocess.py. - Runner distributed skip/all-rank behavior:
flashdreams/tests/test_runner_postprocess.py.
Every pytest test must use exactly one marker: ci_cpu, ci_gpu, or manual.
Prefer fake processor builders for CPU tests instead of loading checkpoints.
Useful focused validation:
uv run pytest flashdreams/tests/test_runner_postprocess.py \
flashdreams/tests/test_postprocess_stream.py \
flashdreams/tests/test_postprocess_presets.py \
integrations/<name>/tests/test_postprocess.py