Created
February 2, 2026 16:19
-
-
Save elbruno/ac875e7c567c573366e5821c64389e8c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| Video Extension Tool | |
| Extends a video by adding extra time using the last frame. | |
| Demo for El Bruno's YouTube channel: https://www.youtube.com/elbruno | |
| """ | |
| import os | |
| import glob | |
| import cv2 | |
| def get_videos_from_folder(folder="."): | |
| """Get video files from the specified folder.""" | |
| video_extensions = ["*.mp4", "*.avi", "*.mov", "*.mkv", "*.wmv", "*.flv"] | |
| videos = [] | |
| for ext in video_extensions: | |
| videos.extend(glob.glob(os.path.join(folder, ext))) | |
| return videos[:5] # Return first 5 videos | |
| def select_video(videos): | |
| """Display video list and let user select one.""" | |
| print("\n📹 Available videos:") | |
| for i, video in enumerate(videos, 1): | |
| default = " (default)" if i == 1 else "" | |
| print(f" {i}. {os.path.basename(video)}{default}") | |
| choice = input("\nSelect a video [1]: ").strip() | |
| if choice == "" or not choice.isdigit(): | |
| return videos[0] | |
| idx = int(choice) - 1 | |
| if 0 <= idx < len(videos): | |
| return videos[idx] | |
| return videos[0] | |
| def select_extra_time(): | |
| """Let user select extra time to add.""" | |
| options = [5, 10, 15] | |
| print("\n⏱️ Select extra time (seconds):") | |
| for i, seconds in enumerate(options, 1): | |
| default = " (default)" if seconds == 5 else "" | |
| print(f" {i}. {seconds} seconds{default}") | |
| choice = input("\nSelect extra time [1]: ").strip() | |
| if choice == "" or not choice.isdigit(): | |
| return 5 | |
| idx = int(choice) - 1 | |
| if 0 <= idx < len(options): | |
| return options[idx] | |
| return 5 | |
| def extend_video(video_path, extra_seconds): | |
| """Extend video by adding extra time using the last frame.""" | |
| print(f"\n🎬 Processing: {os.path.basename(video_path)}") | |
| # Open the video | |
| cap = cv2.VideoCapture(video_path) | |
| if not cap.isOpened(): | |
| raise Exception(f"Cannot open video: {video_path}") | |
| # Get video properties | |
| fps = cap.get(cv2.CAP_PROP_FPS) | |
| width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | |
| height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| original_duration = total_frames / fps | |
| # Generate output filename | |
| base_name = os.path.splitext(os.path.basename(video_path))[0] | |
| ext = os.path.splitext(video_path)[1] | |
| output_path = os.path.join( | |
| os.path.dirname(video_path) or ".", | |
| f"{base_name}_extended{ext}" | |
| ) | |
| # Set up video writer | |
| fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
| out = cv2.VideoWriter(output_path, fourcc, fps, (width, height)) | |
| print("📝 Writing extended video...") | |
| last_frame = None | |
| frame_count = 0 | |
| # Copy all original frames | |
| while True: | |
| ret, frame = cap.read() | |
| if not ret: | |
| break | |
| last_frame = frame.copy() | |
| out.write(frame) | |
| frame_count += 1 | |
| if frame_count % 100 == 0: | |
| print(f" Processed {frame_count}/{total_frames} frames...", end='\r') | |
| print(f" Processed {frame_count}/{total_frames} frames...") | |
| # Add extra frames using the last frame | |
| extra_frames = int(extra_seconds * fps) | |
| print(f" Adding {extra_frames} extra frames ({extra_seconds}s)...") | |
| for i in range(extra_frames): | |
| out.write(last_frame) | |
| if (i + 1) % 100 == 0: | |
| print(f" Added {i + 1}/{extra_frames} extra frames...", end='\r') | |
| print(f" Added {extra_frames}/{extra_frames} extra frames...") | |
| # Clean up | |
| cap.release() | |
| out.release() | |
| new_duration = original_duration + extra_seconds | |
| return output_path, original_duration, new_duration | |
| def format_duration(seconds): | |
| """Format seconds as MM:SS.""" | |
| minutes = int(seconds // 60) | |
| secs = int(seconds % 60) | |
| return f"{minutes:02d}:{secs:02d}" | |
| def main(): | |
| print("=" * 50) | |
| print(" 🎥 Video Extension Tool") | |
| print("=" * 50) | |
| # Get videos from current folder | |
| videos = get_videos_from_folder() | |
| if not videos: | |
| print("\n❌ No video files found in the current folder.") | |
| print(" Supported formats: mp4, avi, mov, mkv, wmv, flv") | |
| return | |
| # Select video | |
| selected_video = select_video(videos) | |
| print(f"\n✅ Selected: {os.path.basename(selected_video)}") | |
| # Select extra time | |
| extra_time = select_extra_time() | |
| print(f"✅ Extra time: {extra_time} seconds") | |
| # Extend the video | |
| try: | |
| output_path, original_duration, new_duration = extend_video( | |
| selected_video, extra_time | |
| ) | |
| # Show results | |
| print("\n" + "=" * 50) | |
| print(" 📊 Results") | |
| print("=" * 50) | |
| print(f" Original duration: {format_duration(original_duration)}") | |
| print(f" New duration: {format_duration(new_duration)}") | |
| print(f" New video: {os.path.basename(output_path)}") | |
| print("=" * 50) | |
| print("\n✅ Video extended successfully!") | |
| except Exception as e: | |
| print(f"\n❌ Error processing video: {e}") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment