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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -125
app.py CHANGED
@@ -3,138 +3,168 @@ 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()
 
3
  import static_ffmpeg
4
  import os
5
  import tempfile
6
+ from datetime import datetime
7
 
8
  # Add static ffmpeg to PATH
9
  static_ffmpeg.add_paths()
10
 
11
  def stitch_media(video_file, audio_file, subtitle_file, crf_quality=23):
12
+ """
13
+ Stitch video, audio, and subtitle files together using ffmpeg
14
+ All files are handled through Gradio's temporary file system
15
+ """
16
+ try:
17
+ # Validate inputs
18
+ if not video_file or not audio_file or not subtitle_file:
19
+ return None, "❌ Please upload all three files (video, audio, subtitle)"
20
+
21
+ # Gradio automatically provides temporary file paths
22
+ video_path = video_file.name if hasattr(video_file, 'name') else video_file
23
+ audio_path = audio_file.name if hasattr(audio_file, 'name') else audio_file
24
+ subtitle_path = subtitle_file.name if hasattr(subtitle_file, 'name') else subtitle_file
25
+
26
+ # Create output file in temp directory
27
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
28
+ output_path = os.path.join(tempfile.gettempdir(), f"stitched_{timestamp}.mp4")
29
+
30
+ # FFmpeg command
31
+ cmd = [
32
+ "ffmpeg",
33
+ "-i", video_path,
34
+ "-i", audio_path,
35
+ "-vf", f"subtitles={subtitle_path}",
36
+ "-map", "0:v",
37
+ "-map", "1:a",
38
+ "-c:v", "libx264",
39
+ "-crf", str(crf_quality),
40
+ "-c:a", "aac",
41
+ "-y",
42
+ output_path
43
+ ]
44
+
45
+ # Execute ffmpeg
46
+ process = subprocess.run(
47
+ cmd,
48
+ check=True,
49
+ capture_output=True,
50
+ text=True
51
+ )
52
+
53
+ # Check if output file was created
54
+ if os.path.exists(output_path):
55
+ file_size = os.path.getsize(output_path) / (1024 * 1024) # Size in MB
56
+ return output_path, f"βœ… Video stitched successfully! (Size: {file_size:.2f} MB)"
57
+ else:
58
+ return None, "❌ Output file was not created"
59
+
60
+ except subprocess.CalledProcessError as e:
61
+ error_msg = f"❌ FFmpeg error:\n{e.stderr[-500:]}" # Show last 500 chars of error
62
+ return None, error_msg
63
+ except Exception as e:
64
+ return None, f"❌ Error: {str(e)}"
65
 
66
  # Create Gradio interface
67
+ with gr.Blocks(title="Video Audio Subtitle Stitcher", theme=gr.themes.Soft()) as app:
68
+ gr.Markdown(
69
+ """
70
+ # 🎬 Video Audio Subtitle Stitcher
71
+
72
+ **Upload your files and stitch them together - No local installation needed!**
73
+
74
+ This app works entirely in your browser. Just upload, click stitch, and download your result.
75
+ """
76
+ )
77
+
78
+ with gr.Row():
79
+ with gr.Column():
80
+ gr.Markdown("### πŸ“€ Upload Files")
81
+
82
+ video_input = gr.File(
83
+ label="πŸ“Ή Video File",
84
+ file_types=[".mp4", ".mov", ".avi", ".mkv"],
85
+ type="filepath"
86
+ )
87
+ audio_input = gr.File(
88
+ label="🎡 Audio File",
89
+ file_types=[".wav", ".mp3", ".aac", ".m4a"],
90
+ type="filepath"
91
+ )
92
+ subtitle_input = gr.File(
93
+ label="πŸ“ Subtitle File (.srt)",
94
+ file_types=[".srt"],
95
+ type="filepath"
96
+ )
97
+
98
+ gr.Markdown("### βš™οΈ Settings")
99
+
100
+ crf_input = gr.Slider(
101
+ minimum=18,
102
+ maximum=28,
103
+ value=23,
104
+ step=1,
105
+ label="Video Quality (CRF)",
106
+ info="Lower = Better quality but larger file"
107
+ )
108
+
109
+ stitch_btn = gr.Button("🎬 Stitch Video", variant="primary", size="lg")
110
+
111
+ gr.Markdown(
112
+ """
113
+ **πŸ’‘ Tips:**
114
+ - CRF 18-20: Excellent quality
115
+ - CRF 23: Balanced (recommended)
116
+ - CRF 26-28: Smaller file size
117
+ """
118
+ )
119
+
120
+ with gr.Column():
121
+ gr.Markdown("### πŸ“₯ Output")
122
+
123
+ status_output = gr.Textbox(
124
+ label="Status",
125
+ placeholder="Upload files and click 'Stitch Video' to begin...",
126
+ lines=3
127
+ )
128
+ video_output = gr.Video(
129
+ label="Result",
130
+ autoplay=False
131
+ )
132
+
133
+ gr.Markdown(
134
+ """
135
+ **Download:** Right-click the video preview and "Save video as..."
136
+ or use the download button in the video player.
137
+ """
138
+ )
139
+
140
+ gr.Markdown(
141
+ """
142
+ ---
143
+ ### πŸ“– How it works:
144
+ 1. **Upload** your video, audio, and subtitle files
145
+ 2. **Adjust** quality settings if needed
146
+ 3. **Click** "Stitch Video" button
147
+ 4. **Wait** for processing (may take a few moments)
148
+ 5. **Preview** and download your result!
149
+
150
+ ### 🎯 Technical Details:
151
+ - Video codec: H.264 (libx264)
152
+ - Audio codec: AAC
153
+ - Output length: Matches shortest stream (video or audio)
154
+ - Subtitles: Burned into video
155
+
156
+ ### ☁️ Cloud Deployment Ready:
157
+ This app can be deployed to Hugging Face Spaces, Google Colab, or any cloud platform!
158
+ """
159
+ )
160
+
161
+ # Connect the button to the function
162
+ stitch_btn.click(
163
+ fn=stitch_media,
164
+ inputs=[video_input, audio_input, subtitle_input, crf_input],
165
+ outputs=[video_output, status_output]
166
+ )
167
 
168
  # Launch the app
169
  if __name__ == "__main__":
170
+ app.launch()