# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: OpenMDW-1.1 from typing import IO, Any, Union import numpy as np import torch from einops import rearrange from PIL import Image as PILImage from torch import Tensor from cosmos_framework.utils.easy_io import easy_io def save_video(grid, video_name, fps=30): import imageio grid = (grid * 255).astype(np.uint8) grid = np.transpose(grid, (1, 2, 3, 0)) imageio.mimsave( video_name, list(grid), format="mp4", fps=float(fps), codec="libx264", pixelformat="yuv420p", macro_block_size=1, ) def save_img_or_video( sample: Tensor, # [C,T,H,W] in [0,1] range save_fp_wo_ext: Union[str, IO[Any]], fps: int = 24, quality=None, ffmpeg_params=None, **kwargs, ) -> None: """ Save a tensor as an image or video file based on shape Args: sample (Tensor): Input tensor with shape (C, T, H, W) in [0, 1] range. save_fp_wo_ext (Union[str, IO[Any]]): File path without extension or file-like object. fps (int): Frames per second for video. Default is 24. """ assert sample.ndim == 4, "Only support 4D tensor" assert isinstance(save_fp_wo_ext, str) or hasattr(save_fp_wo_ext, "write"), ( "save_fp_wo_ext must be a string or file-like object" ) if torch.is_floating_point(sample): sample = sample.clamp(0, 1) else: assert sample.dtype == torch.uint8, "Only support uint8 tensor" sample = sample.float().div(255) if ffmpeg_params is not None: kwargs["ffmpeg_params"] = ffmpeg_params if sample.shape[1] == 1: save_obj = PILImage.fromarray( rearrange((sample.cpu().float().numpy() * 255), "c 1 h w -> h w c").astype(np.uint8), mode="RGB", ) ext = ".jpg" if isinstance(save_fp_wo_ext, str) else "" easy_io.dump( save_obj, f"{save_fp_wo_ext}{ext}" if isinstance(save_fp_wo_ext, str) else save_fp_wo_ext, file_format="jpg", format="JPEG", quality=85 if quality is None else quality, **kwargs, ) else: if quality is not None: kwargs["quality"] = quality save_obj = rearrange((sample.cpu().float().numpy() * 255), "c t h w -> t h w c").astype(np.uint8) ext = ".mp4" if isinstance(save_fp_wo_ext, str) else "" easy_io.dump( save_obj, f"{save_fp_wo_ext}{ext}" if isinstance(save_fp_wo_ext, str) else save_fp_wo_ext, file_format="mp4", format="mp4", fps=fps, **kwargs, )