import subprocess import os from typing import List, Tuple def split_video(input_file: str, output_dir: str, timestamps: List[Tuple[float, float]], frame_perfect: bool = False) -> None: """ Splits a video file into multiple segments based on specified time ranges. Args: input_file (str): The path to the video file to be split. output_dir (str): The directory where the split segments will be saved. timestamps (List[Tuple[float, float]]): A list of tuples representing (start_time, end_time). frame_perfect (bool): If True, skips fast-copy and forces high-quality re-encoding to ensure cuts happen exactly on the requested frame. """ if not os.path.exists(input_file): print(f"Error: Input file not found at {input_file}") return os.makedirs(output_dir, exist_ok=True) print(f"Starting video split process for {input_file}...") for i, (start, end) in enumerate(timestamps): segment_name = f"segment_{i+1:02d}_{start:.2f}s_to_{end:.2f}s.mp4" output_file = os.path.join(output_dir, segment_name) print(f"\n-> Processing segment {i+1}/{len(timestamps)}: {segment_name}") # Method 1: Fast Copy (Lossless, no re-encoding) # Moving -ss BEFORE -i fixes the frozen/corrupted initial frames. fast_command = [ "ffmpeg", "-y", "-ss", str(start), "-i", input_file, "-to", str(end), "-c", "copy", output_file ] # Method 2: High-Quality Re-encode (Frame-perfect fallback) # Used if fast copy fails or if frame-accuracy is explicitly requested. reencode_command = [ "ffmpeg", "-y", "-ss", str(start), "-i", input_file, "-to", str(end), "-c:v", "libx264", "-crf", "18", # High visual quality "-preset", "slow", # Better compression efficiency "-c:a", "aac", "-b:a", "256k", # High-fidelity audio output_file ] try: if frame_perfect: print("Running in frame-perfect mode (re-encoding)...") subprocess.run(reencode_command, check=True, capture_output=True, text=True) else: try: print("Attempting lightning-fast stream copy...") subprocess.run(fast_command, check=True, capture_output=True, text=True) except subprocess.CalledProcessError: print("⚠️ Fast copy failed. Falling back to high-quality re-encode...") subprocess.run(reencode_command, check=True, capture_output=True, text=True) print(f"Successfully created segment: {output_file}") except subprocess.CalledProcessError as e: print(f"❌ Error splitting video segment {i+1}:") print(f"Command failed with return code {e.returncode}") print(f"STDERR: {e.stderr}") except FileNotFoundError: print("-" * 50) print("CRITICAL ERROR: FFmpeg executable not found.") print("Please ensure 'ffmpeg' is installed and accessible in your system's PATH.") print("-" * 50) return def main(): """ Example usage: Assumes 'input.mp4' exists and a 'split_videos' directory is ready. """ # --- CONFIGURATION --- INPUT_VIDEO_PATH = "path/to/your/input_video.mp4" # <<< CHANGE THIS OUTPUT_SEGMENTS_DIR = "output_splits" # <<< CHANGE THIS # Define time segments: [(start_time, end_time), ...] # Times should be floats representing seconds. # Example 1: 0s to 10s, then 10s to 20s TIMESTAMPS: List[Tuple[float, float]] = [ (0.0, 10.0), (15.0, 25.0), (30.0, 35.0) ] # --------------------- if not os.path.exists(INPUT_VIDEO_PATH): print("!!! IMPORTANT !!!") print(f"Please update the 'INPUT_VIDEO_PATH' variable in the main() function with the correct path to your video.") print("!!! Script execution aborted. !!!") return split_video( input_file=INPUT_VIDEO_PATH, output_dir=OUTPUT_SEGMENTS_DIR, timestamps=TIMESTAMPS ) if __name__ == "__main__": main()