Source code for kerb.multimodal.video.processor
"""Video processing and frame extraction.
This module provides video processing, frame extraction, and thumbnail creation.
"""
import os
from pathlib import Path
from typing import List, Optional
from ..types import VideoFormat, VideoInfo
[docs]
def get_video_info(file_path: str) -> VideoInfo:
"""Get detailed information about a video file.
Args:
file_path: Path to the video file
Returns:
VideoInfo: Video information object
Raises:
ImportError: If moviepy is not installed
Examples:
>>> info = get_video_info("video.mp4")
>>> print(f"{info.width}x{info.height} @ {info.fps} FPS")
1920x1080 @ 30.0 FPS
"""
try:
from moviepy.editor import VideoFileClip
except ImportError:
raise ImportError(
"moviepy is required for video processing. Install with: pip install moviepy"
)
video = VideoFileClip(file_path)
ext = Path(file_path).suffix.lower().lstrip(".")
format_map = {
"mp4": VideoFormat.MP4,
"avi": VideoFormat.AVI,
"mov": VideoFormat.MOV,
"mkv": VideoFormat.MKV,
"webm": VideoFormat.WEBM,
"flv": VideoFormat.FLV,
}
video_format = format_map.get(ext, VideoFormat.MP4)
info = VideoInfo(
width=video.w,
height=video.h,
duration_seconds=video.duration,
fps=video.fps,
frame_count=int(video.fps * video.duration),
format=video_format,
size_bytes=os.path.getsize(file_path),
has_audio=video.audio is not None,
)
video.close()
return info
[docs]
def extract_video_frames(
video_path: str,
output_dir: str,
fps: Optional[float] = None,
max_frames: Optional[int] = None,
start_time: float = 0.0,
end_time: Optional[float] = None,
) -> List[str]:
"""Extract frames from a video.
Args:
video_path: Path to the video file
output_dir: Directory to save frames
fps: Frames per second to extract (None for all frames)
max_frames: Maximum number of frames to extract
start_time: Start time in seconds
end_time: End time in seconds (None for end of video)
Returns:
List of paths to extracted frame images
Examples:
>>> frames = extract_video_frames("video.mp4", "frames/", fps=1)
>>> len(frames)
30
"""
try:
from moviepy.editor import VideoFileClip
except ImportError:
raise ImportError(
"moviepy is required for video processing. Install with: pip install moviepy"
)
os.makedirs(output_dir, exist_ok=True)
video = VideoFileClip(video_path)
if end_time is None:
end_time = video.duration
# Calculate frame extraction times
if fps is not None:
interval = 1.0 / fps
times = []
t = start_time
while t < end_time:
times.append(t)
t += interval
if max_frames and len(times) >= max_frames:
break
else:
# Extract all frames
video_fps = video.fps
interval = 1.0 / video_fps
times = []
t = start_time
while t < end_time:
times.append(t)
t += interval
if max_frames and len(times) >= max_frames:
break
frame_paths = []
for i, t in enumerate(times):
frame = video.get_frame(t)
frame_path = os.path.join(output_dir, f"frame_{i:06d}.jpg")
from PIL import Image
img = Image.fromarray(frame)
img.save(frame_path, quality=95)
frame_paths.append(frame_path)
video.close()
return frame_paths
[docs]
def create_video_thumbnail(
video_path: str, output_path: Optional[str] = None, time: float = 1.0
) -> str:
"""Create a thumbnail image from a video.
Args:
video_path: Path to the video file
output_path: Output path for thumbnail (auto-generated if None)
time: Time in seconds to extract frame
Returns:
str: Path to the thumbnail image
Examples:
>>> thumb = create_video_thumbnail("video.mp4")
>>> print(thumb)
'video_thumb.jpg'
"""
try:
from moviepy.editor import VideoFileClip
except ImportError:
raise ImportError(
"moviepy is required for video processing. Install with: pip install moviepy"
)
if output_path is None:
base = os.path.splitext(video_path)[0]
output_path = f"{base}_thumb.jpg"
video = VideoFileClip(video_path)
# Ensure time is within video duration
time = min(time, video.duration - 0.1)
frame = video.get_frame(time)
from PIL import Image
img = Image.fromarray(frame)
img.save(output_path, quality=95)
video.close()
return output_path