Spaces:
Sleeping
Sleeping
Ffmpeg added
Browse files
app.py
CHANGED
@@ -28,22 +28,102 @@ def create_subtitle_clips(subtitles, videosize, fontsize, font, color, debug):
|
|
28 |
#color_clips.append(myclip.with_position(text_position))
|
29 |
return subtitle_clips
|
30 |
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
with gr.Blocks() as demo:
|
49 |
gr.Markdown("Start typing below and then click **Run** to see the progress and final output.")
|
|
|
28 |
#color_clips.append(myclip.with_position(text_position))
|
29 |
return subtitle_clips
|
30 |
|
31 |
+
import subprocess
|
32 |
+
import os
|
33 |
+
|
34 |
+
# Mapping of color names to FFmpeg-compatible hex codes
|
35 |
+
COLOR_MAP = {
|
36 |
+
'white': '#FFFFFF',
|
37 |
+
'yellow': '#FFFF00',
|
38 |
+
'red': '#FF0000',
|
39 |
+
'green': '#00FF00',
|
40 |
+
'blue': '#0000FF',
|
41 |
+
'black': '#000000'
|
42 |
+
}
|
43 |
+
|
44 |
+
def hex_to_ffmpeg_color(hex_code):
|
45 |
+
"""
|
46 |
+
Convert standard hex color (#RRGGBB) to FFmpeg's PrimaryColour format (&HBBGGRR&).
|
47 |
+
|
48 |
+
Args:
|
49 |
+
hex_code (str): Standard hex color code (e.g., '#FFFFFF')
|
50 |
+
Returns:
|
51 |
+
str: FFmpeg color code (e.g., '&HFFFFFF&')
|
52 |
+
"""
|
53 |
+
hex_code = hex_code.lstrip('#')
|
54 |
+
r, g, b = hex_code[0:2], hex_code[2:4], hex_code[4:6]
|
55 |
+
return f'&H{b}{g}{r}&'
|
56 |
+
|
57 |
+
def video_edit(srt, input_video, font_color, font_type, font_size, input_audio=None):
|
58 |
+
"""
|
59 |
+
Burns subtitles into a video using FFmpeg with customizable styling.
|
60 |
+
|
61 |
+
Args:
|
62 |
+
srt (str): Path to SRT subtitle file
|
63 |
+
input_video (dict or str): Input video path or dict with 'video' key
|
64 |
+
font_color (str): Color name (e.g., 'white', 'yellow')
|
65 |
+
font_type (str): Font name for subtitles
|
66 |
+
font_size (int): Font size for subtitles
|
67 |
+
input_audio (str, optional): Path to audio file (if provided)
|
68 |
+
|
69 |
+
Returns:
|
70 |
+
str: Path to output video file
|
71 |
+
"""
|
72 |
+
# Handle input_video as dict or string
|
73 |
+
if isinstance(input_video, dict):
|
74 |
+
video_path = input_video.get('video', '')
|
75 |
+
else:
|
76 |
+
video_path = input_video
|
77 |
+
|
78 |
+
# Validate input
|
79 |
+
if not video_path or not os.path.exists(video_path):
|
80 |
+
raise ValueError("Invalid or missing video file")
|
81 |
+
if not os.path.exists(srt):
|
82 |
+
raise ValueError("Subtitle file not found")
|
83 |
+
|
84 |
+
# Generate output filename
|
85 |
+
input_base = os.path.splitext(video_path)[0]
|
86 |
+
output_video = f"{input_base}_subtitled.mp4"
|
87 |
+
|
88 |
+
# Convert color name to FFmpeg format
|
89 |
+
hex_color = COLOR_MAP.get(font_color.lower())
|
90 |
+
if not hex_color:
|
91 |
+
raise ValueError(f"Unsupported color: {font_color}. Supported colors: {', '.join(COLOR_MAP.keys())}")
|
92 |
+
ffmpeg_color = hex_to_ffmpeg_color(hex_color)
|
93 |
+
|
94 |
+
# Build subtitle style
|
95 |
+
subtitle_style = f"FontName={font_type},FontSize={font_size},PrimaryColour={ffmpeg_color}"
|
96 |
+
fonts_dir = os.path.dirname(srt)
|
97 |
+
|
98 |
+
# Construct FFmpeg command
|
99 |
+
cmd = [
|
100 |
+
'ffmpeg',
|
101 |
+
'-i', video_path, # Input video
|
102 |
+
]
|
103 |
+
|
104 |
+
# Add audio input if provided (though we'll still keep original audio)
|
105 |
+
if input_audio and os.path.exists(input_audio):
|
106 |
+
cmd.extend(['-i', input_audio])
|
107 |
+
|
108 |
+
cmd.extend([
|
109 |
+
'-vf', f"subtitles={srt}:fontsdir={fonts_dir}:force_style='{subtitle_style}'", # Burn subtitles
|
110 |
+
'-c:v', 'libx264', # Video codec
|
111 |
+
'-c:a', 'copy', # Always copy original audio
|
112 |
+
'-r', '24', # Frame rate
|
113 |
+
'-preset', 'ultrafast',# Encoding preset
|
114 |
+
'-y', # Overwrite output
|
115 |
+
output_video
|
116 |
+
])
|
117 |
+
|
118 |
+
# Execute FFmpeg command
|
119 |
+
try:
|
120 |
+
subprocess.run(cmd, check=True, stderr=subprocess.PIPE, universal_newlines=True)
|
121 |
+
except subprocess.CalledProcessError as e:
|
122 |
+
raise RuntimeError(f"FFmpeg failed: {e.stderr}")
|
123 |
+
|
124 |
+
print(f"Video processed successfully: {output_video}")
|
125 |
+
return output_video
|
126 |
+
|
127 |
|
128 |
with gr.Blocks() as demo:
|
129 |
gr.Markdown("Start typing below and then click **Run** to see the progress and final output.")
|