|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import glob |
|
from dataclasses import dataclass |
|
|
|
import imageio |
|
import numpy as np |
|
|
|
from .log import log |
|
|
|
|
|
@dataclass |
|
class VideoData: |
|
frames: np.ndarray |
|
fps: int |
|
duration: int |
|
|
|
|
|
def get_video_filepaths(input_dir: str) -> list[str]: |
|
"""Get a list of filepaths for all videos in the input directory.""" |
|
paths = glob.glob(f"{input_dir}/**/*.mp4", recursive=True) |
|
paths += glob.glob(f"{input_dir}/**/*.avi", recursive=True) |
|
paths += glob.glob(f"{input_dir}/**/*.mov", recursive=True) |
|
paths = sorted(paths) |
|
log.debug(f"Found {len(paths)} videos") |
|
return paths |
|
|
|
|
|
def read_video(filepath: str) -> VideoData: |
|
"""Read a video file and extract its frames and metadata.""" |
|
try: |
|
reader = imageio.get_reader(filepath, "ffmpeg") |
|
except Exception as e: |
|
raise ValueError(f"Failed to read video file: {filepath}") from e |
|
|
|
|
|
try: |
|
metadata = reader.get_meta_data() |
|
fps = metadata.get("fps") |
|
duration = metadata.get("duration") |
|
except Exception as e: |
|
reader.close() |
|
raise ValueError(f"Failed to extract metadata from video file: {filepath}") from e |
|
|
|
|
|
try: |
|
frames = np.array([frame for frame in reader]) |
|
except Exception as e: |
|
raise ValueError(f"Failed to extract frames from video file: {filepath}") from e |
|
finally: |
|
reader.close() |
|
|
|
return VideoData(frames=frames, fps=fps, duration=duration) |
|
|
|
|
|
def save_video(filepath: str, frames: np.ndarray, fps: int) -> None: |
|
"""Save a video file from a sequence of frames.""" |
|
try: |
|
writer = imageio.get_writer(filepath, fps=fps, macro_block_size=1) |
|
for frame in frames: |
|
writer.append_data(frame) |
|
except Exception as e: |
|
raise ValueError(f"Failed to save video file to {filepath}") from e |
|
finally: |
|
writer.close() |
|
|