from typing import Optional, List, Tuple from functools import lru_cache import cv2 from facefusion.typing import Frame, Resolution from facefusion.choices import video_template_sizes from facefusion.filesystem import is_image, is_video def get_video_frame(video_path : str, frame_number : int = 0) -> Optional[Frame]: if is_video(video_path): video_capture = cv2.VideoCapture(video_path) if video_capture.isOpened(): frame_total = video_capture.get(cv2.CAP_PROP_FRAME_COUNT) video_capture.set(cv2.CAP_PROP_POS_FRAMES, min(frame_total, frame_number - 1)) has_frame, frame = video_capture.read() video_capture.release() if has_frame: return frame return None def count_video_frame_total(video_path : str) -> int: if is_video(video_path): video_capture = cv2.VideoCapture(video_path) if video_capture.isOpened(): video_frame_total = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT)) video_capture.release() return video_frame_total return 0 def detect_video_fps(video_path : str) -> Optional[float]: if is_video(video_path): video_capture = cv2.VideoCapture(video_path) if video_capture.isOpened(): video_fps = video_capture.get(cv2.CAP_PROP_FPS) video_capture.release() return video_fps return None def detect_video_resolution(video_path : str) -> Optional[Tuple[float, float]]: if is_video(video_path): video_capture = cv2.VideoCapture(video_path) if video_capture.isOpened(): width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH) height = video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT) video_capture.release() return width, height return None def create_video_resolutions(video_path : str) -> Optional[List[str]]: temp_resolutions = [] video_resolutions = [] video_resolution = detect_video_resolution(video_path) if video_resolution: width, height = video_resolution temp_resolutions.append(normalize_resolution(video_resolution)) for template_size in video_template_sizes: if width > height: temp_resolutions.append(normalize_resolution((template_size * width / height, template_size))) else: temp_resolutions.append(normalize_resolution((template_size, template_size * height / width))) temp_resolutions = sorted(set(temp_resolutions)) for temp in temp_resolutions: video_resolutions.append(pack_resolution(temp)) return video_resolutions return None def normalize_resolution(resolution : Tuple[float, float]) -> Resolution: width, height = resolution if width and height: normalize_width = round(width / 2) * 2 normalize_height = round(height / 2) * 2 return normalize_width, normalize_height return 0, 0 def pack_resolution(resolution : Tuple[float, float]) -> str: width, height = normalize_resolution(resolution) return str(width) + 'x' + str(height) def unpack_resolution(resolution : str) -> Resolution: width, height = map(int, resolution.split('x')) return width, height def resize_frame_resolution(frame : Frame, max_width : int, max_height : int) -> Frame: height, width = frame.shape[:2] if height > max_height or width > max_width: scale = min(max_height / height, max_width / width) new_width = int(width * scale) new_height = int(height * scale) return cv2.resize(frame, (new_width, new_height)) return frame def normalize_frame_color(frame : Frame) -> Frame: return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) @lru_cache(maxsize = 128) def read_static_image(image_path : str) -> Optional[Frame]: return read_image(image_path) def read_static_images(image_paths : List[str]) -> Optional[List[Frame]]: frames = [] if image_paths: for image_path in image_paths: frames.append(read_static_image(image_path)) return frames def read_image(image_path : str) -> Optional[Frame]: if is_image(image_path): return cv2.imread(image_path) return None def write_image(image_path : str, frame : Frame) -> bool: if image_path: return cv2.imwrite(image_path, frame) return False