File size: 6,041 Bytes
519351f b7c85d5 519351f b7c85d5 519351f ce16ace 519351f c63c39e 73b4be4 519351f b7c85d5 c63c39e 519351f b7c85d5 519351f b7c85d5 c63c39e 519351f b7c85d5 ce16ace b7c85d5 73b4be4 c63c39e b7c85d5 519351f ce16ace c63c39e 519351f ce16ace 519351f c63c39e 519351f ce16ace 519351f ce16ace 519351f ce16ace 519351f ce16ace c63c39e ce16ace b7c85d5 ce16ace c63c39e ce16ace b7c85d5 c63c39e 519351f ce16ace 519351f b7c85d5 ce16ace b7c85d5 ce16ace b7c85d5 ce16ace 519351f ce16ace | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | import os
import subprocess
import uuid
import imageio_ffmpeg
from typing import List, Optional, Tuple, Any
# Import existing functions - avoid circular imports
from ffmpeg_utils import extract_clip_ffmpeg, get_video_info_ffmpeg
def should_use_ffmpeg_processing(timestamps, custom_dims, export_audio, bg_music, output_format, subtitle_path=None) -> bool:
# FFmpeg can now handle background music mixing and all ShortsStyle!
# Default to True to use FFmpeg optimization for most cases
return True
def process_single_clip_hybrid(video_path: str, start_time: float, end_time: float, clip_id: str,
output_format: Any, custom_dims: Optional[Any] = None,
export_audio: bool = True, bg_music: Optional[str] = None,
aspect_ratio: Optional[Any] = None,
subtitle_path: Optional[str] = None) -> str:
"""
Hybrid clip processing: FFmpeg for speed, MoviePy for features
"""
try:
from schemas import ShortsStyle, AspectRatio
from routers.video import PROCESSED_DIR
# Generate output path in the PROCESSED folder
output_path = os.path.join(PROCESSED_DIR, f"clip_{clip_id}.mp4")
# Check if we can use FFmpeg for this clip
can_use_ffmpeg = should_use_ffmpeg_processing(
[type('obj', (object,), {'start_time': start_time, 'end_time': end_time})],
custom_dims, export_audio, bg_music, output_format, subtitle_path=subtitle_path
)
if can_use_ffmpeg:
# Use FFmpeg for speed
print(f"π Using FFmpeg for clip {clip_id} (Style: {output_format})")
# Map custom_dims or output_format to style
style = output_format if isinstance(output_format, ShortsStyle) else None
return extract_clip_ffmpeg(
video_path, start_time, end_time, output_path,
target_width=custom_dims.width if hasattr(custom_dims, 'width') else None,
target_height=custom_dims.height if hasattr(custom_dims, 'height') else None,
include_audio=True, # Video should always have audio if it exists
style=style,
aspect_ratio=aspect_ratio,
bg_music_path=bg_music,
video_volume=custom_dims.video_volume if hasattr(custom_dims, 'video_volume') else 1.0,
music_volume=custom_dims.music_volume if hasattr(custom_dims, 'music_volume') else 0.2,
loop_music=custom_dims.loop_music if hasattr(custom_dims, 'loop_music') else True,
subtitle_path=subtitle_path
)
else:
# Use MoviePy for features (fallback)
print(f"π¬ Using MoviePy for clip {clip_id}")
# Import here to avoid circular imports
from video_processor import process_single_clip as moviepy_process_single_clip
return moviepy_process_single_clip(video_path, start_time, end_time, clip_id, output_format, custom_dims, export_audio, bg_music, subtitle_path=subtitle_path)
except Exception as e:
print(f"β Hybrid processing failed for clip {clip_id}: {e}")
raise
def process_video_hybrid(video_path: str, timestamps, output_format, custom_dims=None,
export_audio=True, bg_music=None, aspect_ratio=None,
subtitle_paths: Optional[List[str]] = None) -> tuple:
"""
Process video using hybrid approach (FFmpeg + MoviePy)
Returns: (clip_paths, audio_paths)
"""
clip_paths = []
audio_paths = []
try:
# Create temp directory
os.makedirs("temp_videos", exist_ok=True)
# Check if we can use FFmpeg for the entire video
# Passing None for subtitle_path here as it's checked per-clip in process_single_clip_hybrid
can_use_ffmpeg = should_use_ffmpeg_processing(timestamps, custom_dims, export_audio, bg_music, output_format)
if can_use_ffmpeg:
print(f"π Using FFmpeg optimization for entire video (Style: {output_format})")
# Process all clips with FFmpeg
for i, ts in enumerate(timestamps):
current_subtitle = subtitle_paths[i] if subtitle_paths and i < len(subtitle_paths) else None
clip_path = process_single_clip_hybrid(
video_path, ts.start_time, ts.end_time, f"hybrid_{i}_{uuid.uuid4().hex[:4]}",
output_format, custom_dims, export_audio, bg_music,
aspect_ratio=aspect_ratio,
subtitle_path=current_subtitle
)
clip_paths.append(clip_path)
# If separate audio export is requested
if export_audio:
from routers.video import AUDIO_DIR
audio_path = os.path.join(AUDIO_DIR, f"audio_hybrid_{i}_{uuid.uuid4().hex[:4]}.mp3")
# Extract audio using FFmpeg
cmd = [
imageio_ffmpeg.get_ffmpeg_exe(),
'-i', clip_path,
'-vn',
'-acodec', 'libmp3lame',
'-y', audio_path
]
subprocess.run(cmd, check=True, capture_output=True)
audio_paths.append(audio_path)
else:
print("π¬ Using MoviePy for complex processing")
# Fallback to MoviePy for complex cases
# This will be handled by the calling function
return [], []
return clip_paths, audio_paths
except Exception as e:
print(f"β Hybrid video processing failed: {e}")
# Clean up any partial results
for path in clip_paths + audio_paths:
if os.path.exists(path):
os.remove(path)
return [], [] |