Spaces:
Build error
Build error
| import cv2 | |
| import subprocess | |
| from moviepy.editor import VideoFileClip, TextClip, CompositeVideoClip, AudioFileClip | |
| from moviepy.video.fx import all as vfx | |
| import numpy as np | |
| from pathlib import Path | |
| import tempfile | |
| class VideoProcessor: | |
| def __init__(self): | |
| self.temp_dir = tempfile.mkdtemp() | |
| def extract_audio(self, video_path): | |
| """Extract audio from video file""" | |
| try: | |
| video = VideoFileClip(video_path) | |
| audio_path = Path(self.temp_dir) / "audio.wav" | |
| video.audio.write_audiofile(str(audio_path), logger=None) | |
| video.close() | |
| return str(audio_path) | |
| except Exception as e: | |
| raise Exception(f"Audio extraction failed: {str(e)}") | |
| def extract_clip(self, video_path, start_time, end_time): | |
| """Extract a segment from video""" | |
| try: | |
| video = VideoFileClip(video_path) | |
| clip = video.subclip(start_time, end_time) | |
| # Resize to 9:16 for shorts | |
| target_width = 1080 | |
| target_height = 1920 | |
| # Calculate scaling | |
| scale = max(target_width / clip.w, target_height / clip.h) | |
| new_w = int(clip.w * scale) | |
| new_h = int(clip.h * scale) | |
| # Resize and crop | |
| clip_resized = clip.resize((new_w, new_h)) | |
| # Center crop | |
| x_center = new_w / 2 | |
| y_center = new_h / 2 | |
| x1 = int(x_center - target_width / 2) | |
| y1 = int(y_center - target_height / 2) | |
| clip_cropped = clip_resized.crop( | |
| x1=x1, y1=y1, | |
| x2=x1 + target_width, | |
| y2=y1 + target_height | |
| ) | |
| output_path = Path(self.temp_dir) / f"clip_{start_time}_{end_time}.mp4" | |
| clip_cropped.write_videofile( | |
| str(output_path), | |
| codec='libx264', | |
| audio_codec='aac', | |
| logger=None | |
| ) | |
| video.close() | |
| clip.close() | |
| clip_resized.close() | |
| clip_cropped.close() | |
| return str(output_path) | |
| except Exception as e: | |
| raise Exception(f"Clip extraction failed: {str(e)}") | |
| def add_captions(self, video_path, captions_data): | |
| """Add animated captions to video""" | |
| try: | |
| video = VideoFileClip(video_path) | |
| clips = [video] | |
| for caption in captions_data['captions']: | |
| # Create text clip | |
| txt_clip = TextClip( | |
| caption['text'], | |
| fontsize=captions_data['fontsize'], | |
| color=captions_data['color'], | |
| stroke_color=captions_data['stroke_color'], | |
| stroke_width=captions_data['stroke_width'], | |
| font='Arial-Bold', | |
| method='caption', | |
| size=(video.w * 0.9, None) | |
| ) | |
| # Position and timing | |
| txt_clip = txt_clip.set_position(('center', 'center')) | |
| txt_clip = txt_clip.set_start(caption['start']) | |
| txt_clip = txt_clip.set_duration(caption['duration']) | |
| # Add animation | |
| if captions_data['animation'] == 'pop': | |
| txt_clip = txt_clip.crossfadein(0.2) | |
| clips.append(txt_clip) | |
| # Compose final video | |
| final_video = CompositeVideoClip(clips) | |
| output_path = video_path.replace('.mp4', '_captioned.mp4') | |
| final_video.write_videofile( | |
| output_path, | |
| codec='libx264', | |
| audio_codec='aac', | |
| logger=None | |
| ) | |
| video.close() | |
| final_video.close() | |
| return output_path | |
| except Exception as e: | |
| raise Exception(f"Caption addition failed: {str(e)}") | |
| def add_sound_effects(self, video_path, sound_effects): | |
| """Add sound effects to video at specific timestamps""" | |
| try: | |
| # This would integrate with sound effect library | |
| # For now, return original video | |
| return video_path | |
| except Exception as e: | |
| raise Exception(f"Sound effect addition failed: {str(e)}") |