sampleacc-3003 commited on
Commit
3f9009e
Β·
verified Β·
1 Parent(s): 11fd18d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -0
app.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import static_ffmpeg
4
+ import os
5
+ import tempfile
6
+
7
+ # Add static ffmpeg to PATH
8
+ static_ffmpeg.add_paths()
9
+
10
+ def stitch_media(video_file, audio_file, subtitle_file, crf_quality=23):
11
+ """
12
+ Stitch video, audio, and subtitle files together using ffmpeg
13
+
14
+ Args:
15
+ video_file: Path to video file (.mp4)
16
+ audio_file: Path to audio file (.wav)
17
+ subtitle_file: Path to subtitle file (.srt)
18
+ crf_quality: Video quality (0-51, lower is better, default: 23)
19
+
20
+ Returns:
21
+ Path to the output video file and status message
22
+ """
23
+ try:
24
+ # Validate inputs
25
+ if not video_file or not audio_file or not subtitle_file:
26
+ return None, "❌ Please upload all three files (video, audio, subtitle)"
27
+
28
+ # Create temporary output file
29
+ output_dir = tempfile.gettempdir()
30
+ output_path = os.path.join(output_dir, f"stitched_video_{os.getpid()}.mp4")
31
+
32
+ # Build ffmpeg command
33
+ # ffmpeg -i video.mp4 -i audio.wav -vf "subtitles=audio.srt" -map 0:v -map 1:a -c:v libx264 -crf 23 -c:a aac -y res.mp4
34
+ cmd = [
35
+ "ffmpeg",
36
+ "-i", video_file,
37
+ "-i", audio_file,
38
+ "-vf", f"subtitles={subtitle_file}",
39
+ "-map", "0:v",
40
+ "-map", "1:a",
41
+ "-c:v", "libx264",
42
+ "-crf", str(crf_quality),
43
+ "-c:a", "aac",
44
+ "-y",
45
+ output_path
46
+ ]
47
+
48
+ # Execute ffmpeg
49
+ result = subprocess.run(
50
+ cmd,
51
+ check=True,
52
+ capture_output=True,
53
+ text=True
54
+ )
55
+
56
+ return output_path, "βœ… Video stitched successfully!"
57
+
58
+ except subprocess.CalledProcessError as e:
59
+ error_msg = f"❌ FFmpeg error: {e.stderr}"
60
+ return None, error_msg
61
+ except Exception as e:
62
+ return None, f"❌ Error: {str(e)}"
63
+
64
+ # Create Gradio interface
65
+ with gr.Blocks(title="Video Audio Subtitle Stitcher") as app:
66
+ gr.Markdown(
67
+ """
68
+ # 🎬 Video Audio Subtitle Stitcher
69
+ Upload a video, audio, and subtitle file to stitch them together using FFmpeg.
70
+
71
+ **The video length will be determined by the shortest stream (video or audio).**
72
+ """
73
+ )
74
+
75
+ with gr.Row():
76
+ with gr.Column():
77
+ video_input = gr.File(
78
+ label="πŸ“Ή Video File (.mp4)",
79
+ file_types=[".mp4", ".mov", ".avi", ".mkv"]
80
+ )
81
+ audio_input = gr.File(
82
+ label="🎡 Audio File (.wav)",
83
+ file_types=[".wav", ".mp3", ".aac", ".m4a"]
84
+ )
85
+ subtitle_input = gr.File(
86
+ label="πŸ“ Subtitle File (.srt)",
87
+ file_types=[".srt"]
88
+ )
89
+
90
+ crf_input = gr.Slider(
91
+ minimum=18,
92
+ maximum=28,
93
+ value=23,
94
+ step=1,
95
+ label="🎨 Video Quality (CRF: lower = better quality, larger file)",
96
+ info="Recommended: 18-23 for high quality, 23-28 for smaller files"
97
+ )
98
+
99
+ stitch_btn = gr.Button("🎬 Stitch Video", variant="primary", size="lg")
100
+
101
+ with gr.Column():
102
+ status_output = gr.Textbox(
103
+ label="Status",
104
+ placeholder="Status will appear here..."
105
+ )
106
+ video_output = gr.Video(
107
+ label="Output Video",
108
+ autoplay=False
109
+ )
110
+
111
+ # Info section
112
+ gr.Markdown(
113
+ """
114
+ ### πŸ“‹ How it works:
115
+ - **Video**: Takes video stream from this file
116
+ - **Audio**: Replaces the video's audio with this file
117
+ - **Subtitle**: Overlays subtitles from SRT file on the video
118
+
119
+ ### βš™οΈ Settings:
120
+ - **CRF (Constant Rate Factor)**: Controls video quality
121
+ - 18-23: High quality (larger files)
122
+ - 23-28: Good quality (smaller files)
123
+ - Default: 23 (balanced)
124
+
125
+ ### 🎯 Output:
126
+ - Codec: H.264 (libx264) for video, AAC for audio
127
+ - Length: Determined by shortest stream
128
+ """
129
+ )
130
+
131
+ # Connect the button to the function
132
+ stitch_btn.click(
133
+ fn=stitch_media,
134
+ inputs=[video_input, audio_input, subtitle_input, crf_input],
135
+ outputs=[video_output, status_output]
136
+ )
137
+
138
+ # Launch the app
139
+ if __name__ == "__main__":
140
+ app.launch()