mirror of
https://github.com/hanzoai/live.git
synced 2026-10-30 18:29:41 +00:00
87 lines
2.8 KiB
Python
87 lines
2.8 KiB
Python
import os
|
|
import time
|
|
|
|
import torch
|
|
from einops import rearrange
|
|
|
|
from ..interface import Pipeline, Requirements
|
|
from ..process import postprocess_chunk
|
|
from ..video import load_video
|
|
|
|
|
|
class VodPipeline(Pipeline):
|
|
"""VOD pipeline for video on demand processing"""
|
|
|
|
def __init__(
|
|
self,
|
|
height: int = 512,
|
|
width: int = 512,
|
|
device: torch.device | None = None,
|
|
dtype: torch.dtype = torch.bfloat16,
|
|
output_fps: int = 30,
|
|
video_path: str = os.path.join(os.path.dirname(__file__), "vod.mp4"),
|
|
):
|
|
self.height = height
|
|
self.width = width
|
|
self.device = device if device is not None else torch.device("cuda")
|
|
self.dtype = dtype
|
|
self.output_fps = output_fps
|
|
self.prompts = None
|
|
self.video_path = video_path
|
|
self.video_frames = None
|
|
self.current_frame_index = 0
|
|
self._load_video()
|
|
|
|
def _load_video(self):
|
|
"""Load video frames from the specified video file."""
|
|
if not os.path.exists(self.video_path):
|
|
print(
|
|
f"Error: Video file {self.video_path} not found. Using gray frames as fallback."
|
|
)
|
|
return
|
|
|
|
try:
|
|
# Load video as tensor with shape [C, T, H, W]
|
|
video_tensor = load_video(
|
|
self.video_path,
|
|
resize_hw=(self.height, self.width),
|
|
normalize=False, # We'll handle normalization in the call method
|
|
)
|
|
|
|
# Convert to [T, C, H, W] format for easier indexing
|
|
self.video_frames = rearrange(video_tensor, "C T H W -> T C H W")
|
|
print(f"Loaded {self.video_frames.shape[0]} frames from {self.video_path}")
|
|
except Exception as e:
|
|
print(
|
|
f"Error loading video {self.video_path}: {e}. Using gray frames as fallback."
|
|
)
|
|
|
|
def prepare(self, should_prepare: bool = False, **kwargs) -> Requirements | None:
|
|
return None
|
|
|
|
def __call__(
|
|
self, input: torch.Tensor | list[torch.Tensor] | None = None, **kwargs
|
|
) -> torch.Tensor:
|
|
# Simulate the inference delay
|
|
time.sleep(1 / self.output_fps)
|
|
|
|
# Get the next frame from the video
|
|
frame_idx = self.current_frame_index % self.video_frames.shape[0]
|
|
frame = self.video_frames[frame_idx] # [C, H, W]
|
|
|
|
# Normalize to [-1, 1] range
|
|
frame = frame / 255.0 * 2.0 - 1.0
|
|
|
|
# Move to device and convert dtype
|
|
frame = frame.to(device=self.device, dtype=self.dtype)
|
|
|
|
# Add time dimension: [C, H, W] -> [1, C, H, W]
|
|
video_frames = frame.unsqueeze(0).unsqueeze(0) # [1, 1, C, H, W]
|
|
|
|
self.current_frame_index += 1
|
|
|
|
# Rearrange to BTCWH format as expected by postprocess_chunk
|
|
chunk = rearrange(video_frames, "B T C H W -> B T C H W")
|
|
|
|
return postprocess_chunk(chunk)
|