factblink514 commited on
Commit
e91dd89
·
verified ·
1 Parent(s): 819c942

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -0
app.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import os
4
+ import uuid
5
+ import shutil
6
+
7
+ TEMP_DIR = "temp_work"
8
+ os.makedirs(TEMP_DIR, exist_ok=True)
9
+
10
+
11
+ def run_cmd(cmd):
12
+ """Run a shell command and raise readable error if it fails."""
13
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
14
+ if result.returncode != 0:
15
+ raise RuntimeError(f"FFmpeg error:\n{result.stderr[-1500:]}")
16
+ return result
17
+
18
+
19
+ def merge_videos(video1, video2, pitch_factor, apply_deep_voice, target_height, progress=gr.Progress()):
20
+ if video1 is None or video2 is None:
21
+ raise gr.Error("Dono videos upload karo bhai!")
22
+
23
+ session_id = str(uuid.uuid4())[:8]
24
+ work_dir = os.path.join(TEMP_DIR, session_id)
25
+ os.makedirs(work_dir, exist_ok=True)
26
+
27
+ v1_norm = os.path.join(work_dir, "v1_norm.mp4")
28
+ v2_norm = os.path.join(work_dir, "v2_norm.mp4")
29
+ concat_list = os.path.join(work_dir, "list.txt")
30
+ joined = os.path.join(work_dir, "joined.mp4")
31
+ final_output = os.path.join(work_dir, "final_output.mp4")
32
+
33
+ try:
34
+ progress(0.1, desc="Video 1 normalize ho raha hai...")
35
+ # Normalize video1 - same resolution, fps, codec settings for safe concat
36
+ run_cmd(
37
+ f'ffmpeg -y -i "{video1}" '
38
+ f'-vf "scale=-2:{target_height},fps=30" '
39
+ f'-c:v libx264 -preset veryfast -crf 23 '
40
+ f'-c:a aac -ar 44100 -ac 2 -b:a 128k '
41
+ f'"{v1_norm}"'
42
+ )
43
+
44
+ progress(0.3, desc="Video 2 normalize ho raha hai...")
45
+ run_cmd(
46
+ f'ffmpeg -y -i "{video2}" '
47
+ f'-vf "scale=-2:{target_height},fps=30" '
48
+ f'-c:v libx264 -preset veryfast -crf 23 '
49
+ f'-c:a aac -ar 44100 -ac 2 -b:a 128k '
50
+ f'"{v2_norm}"'
51
+ )
52
+
53
+ progress(0.55, desc="Dono videos join ho rahe hain...")
54
+ with open(concat_list, "w") as f:
55
+ f.write(f"file '{os.path.abspath(v1_norm)}'\n")
56
+ f.write(f"file '{os.path.abspath(v2_norm)}'\n")
57
+
58
+ run_cmd(
59
+ f'ffmpeg -y -f concat -safe 0 -i "{concat_list}" '
60
+ f'-c copy "{joined}"'
61
+ )
62
+
63
+ progress(0.8, desc="Voice effect apply ho raha hai...")
64
+ if apply_deep_voice:
65
+ # asetrate changes pitch+speed, aresample fixes sample rate,
66
+ # atempo compensates speed back to normal -> pitch changes, speed stays same
67
+ new_rate = int(44100 * pitch_factor)
68
+ run_cmd(
69
+ f'ffmpeg -y -i "{joined}" '
70
+ f'-af "asetrate={new_rate},aresample=44100,atempo={1/pitch_factor:.4f}" '
71
+ f'-c:v copy -c:a aac -b:a 128k '
72
+ f'"{final_output}"'
73
+ )
74
+ else:
75
+ shutil.copy(joined, final_output)
76
+
77
+ progress(1.0, desc="Done!")
78
+ return final_output
79
+
80
+ except Exception as e:
81
+ raise gr.Error(str(e))
82
+
83
+
84
+ def cleanup_old_sessions():
85
+ # Optional: clear temp dir on each fresh load to save disk space on free tier
86
+ if os.path.exists(TEMP_DIR):
87
+ for d in os.listdir(TEMP_DIR):
88
+ shutil.rmtree(os.path.join(TEMP_DIR, d), ignore_errors=True)
89
+
90
+
91
+ with gr.Blocks(title="Video Merger + Deep Voice") as demo:
92
+ gr.Markdown("# 🎬 2 Video Merge + Deep Voice Tool")
93
+ gr.Markdown("Pehla video upload karo (aage chalega), dusra video upload karo (piche chalega). Chaaho to deep voice effect bhi laga sakte ho.")
94
+
95
+ with gr.Row():
96
+ video1_input = gr.Video(label="Video 1 (Aage / Pehle chalega)")
97
+ video2_input = gr.Video(label="Video 2 (Piche / Baad me chalega)")
98
+
99
+ with gr.Row():
100
+ apply_deep_voice = gr.Checkbox(label="Deep Voice Effect Lagao", value=True)
101
+ pitch_slider = gr.Slider(
102
+ minimum=0.6, maximum=0.95, value=0.85, step=0.01,
103
+ label="Pitch Level (kam value = zyada deep voice)"
104
+ )
105
+ height_dropdown = gr.Dropdown(
106
+ choices=["480", "720", "1080"], value="720",
107
+ label="Output Resolution (kam = fast processing)"
108
+ )
109
+
110
+ merge_btn = gr.Button("🔥 Merge Karo", variant="primary")
111
+ output_video = gr.Video(label="Final Output")
112
+
113
+ merge_btn.click(
114
+ fn=merge_videos,
115
+ inputs=[video1_input, video2_input, pitch_slider, apply_deep_voice, height_dropdown],
116
+ outputs=output_video
117
+ )
118
+
119
+ if __name__ == "__main__":
120
+ cleanup_old_sessions()
121
+ demo.launch()