Ricky01anjay commited on
Commit
30d90ab
·
verified ·
1 Parent(s): b730c49

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -18
app.py CHANGED
@@ -3,14 +3,12 @@ import uuid
3
  import requests
4
  import shutil
5
  import subprocess
6
- import traceback
7
- import cv2 # Tambahkan import cv2
8
  from fastapi import FastAPI, UploadFile, File, Form, HTTPException
9
  from fastapi.responses import HTMLResponse, FileResponse
10
  from vidstab import VidStab
11
 
12
  # --- FIX UNTUK ERROR HEADLESS OPENCV ---
13
- # Mencegah vidstab memanggil fungsi GUI yang menyebabkan crash di server (cvDestroyAllWindows)
14
  cv2.destroyAllWindows = lambda: None
15
  cv2.imshow = lambda *args, **kwargs: None
16
  cv2.waitKey = lambda *args, **kwargs: 1
@@ -31,7 +29,7 @@ async def index():
31
  <head>
32
  <meta charset="UTF-8">
33
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
34
- <title>AI Video Stabilizer</title>
35
  <script src="https://cdn.tailwindcss.com"></script>
36
  <style>
37
  .loader { border-top-color: #4f46e5; animation: spinner 1.5s linear infinite; }
@@ -40,8 +38,8 @@ async def index():
40
  </head>
41
  <body class="bg-slate-50 min-h-screen flex flex-col items-center p-4 font-sans">
42
  <div class="w-full max-w-md bg-white rounded-3xl shadow-2xl p-8 mt-10 border border-slate-100">
43
- <h1 class="text-3xl font-black text-center text-indigo-600 mb-2">STABILIZER</h1>
44
- <p class="text-center text-slate-400 text-sm mb-8">AI Video Anti-Shake</p>
45
 
46
  <form id="uploadForm" class="space-y-6">
47
  <div class="group relative border-2 border-dashed border-slate-200 rounded-2xl p-8 text-center hover:border-indigo-400 transition-colors">
@@ -71,7 +69,10 @@ async def index():
71
  <div id="status" class="mt-8 hidden">
72
  <div class="flex flex-col items-center justify-center space-y-4">
73
  <div class="loader ease-linear rounded-full border-4 border-t-4 border-slate-200 h-12 w-12"></div>
74
- <p class="text-indigo-600 font-bold text-sm animate-pulse text-center">AI sedang bekerja...<br><span class="text-[10px] text-slate-400">Menganalisis guncangan & re-encoding</span></p>
 
 
 
75
  </div>
76
  </div>
77
 
@@ -137,14 +138,11 @@ async def index():
137
  async def stabilize_video(file: UploadFile = File(None), url: str = Form(None)):
138
  job_id = str(uuid.uuid4())
139
  input_path = os.path.join(UPLOAD_DIR, f"{job_id}_in.mp4")
140
-
141
- # FIX: Ubah ekstensi raw dari .mp4 ke .avi.
142
- # Karena OpenCV menggunakan MJPG secara default, format ini sangat kompatibel dengan kontainer .avi
143
  raw_output_path = os.path.join(OUTPUT_DIR, f"{job_id}_raw.avi")
144
  final_output_path = os.path.join(OUTPUT_DIR, f"{job_id}_final.mp4")
145
 
146
  try:
147
- # 1. Simpan Input
148
  if file:
149
  with open(input_path, "wb") as buffer:
150
  shutil.copyfileobj(file.file, buffer)
@@ -158,16 +156,37 @@ async def stabilize_video(file: UploadFile = File(None), url: str = Form(None)):
158
 
159
  # 2. Proses Stabilisasi (VidStab)
160
  stabilizer = VidStab()
161
- # playback=False ditambahkan untuk memastikan tidak memanggil window GUI
162
- stabilizer.stabilize(input_path=input_path, output_path=raw_output_path, playback=False)
163
-
164
- # 3. Konversi dari AVI ke H.264 MP4 (agar bisa diputar di Browser/Mobile)
 
 
 
 
 
 
 
 
 
 
165
  ffmpeg_cmd = [
166
- 'ffmpeg', '-y', '-i', raw_output_path,
167
- '-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '25',
168
- '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-movflags', '+faststart',
 
 
 
 
 
 
 
 
 
169
  final_output_path
170
  ]
 
 
171
  subprocess.run(ffmpeg_cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
172
 
173
  # 4. Cleanup file sementara
 
3
  import requests
4
  import shutil
5
  import subprocess
6
+ import cv2
 
7
  from fastapi import FastAPI, UploadFile, File, Form, HTTPException
8
  from fastapi.responses import HTMLResponse, FileResponse
9
  from vidstab import VidStab
10
 
11
  # --- FIX UNTUK ERROR HEADLESS OPENCV ---
 
12
  cv2.destroyAllWindows = lambda: None
13
  cv2.imshow = lambda *args, **kwargs: None
14
  cv2.waitKey = lambda *args, **kwargs: 1
 
29
  <head>
30
  <meta charset="UTF-8">
31
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
32
+ <title>AI Video Stabilizer Pro</title>
33
  <script src="https://cdn.tailwindcss.com"></script>
34
  <style>
35
  .loader { border-top-color: #4f46e5; animation: spinner 1.5s linear infinite; }
 
38
  </head>
39
  <body class="bg-slate-50 min-h-screen flex flex-col items-center p-4 font-sans">
40
  <div class="w-full max-w-md bg-white rounded-3xl shadow-2xl p-8 mt-10 border border-slate-100">
41
+ <h1 class="text-3xl font-black text-center text-indigo-600 mb-2">STABILIZER <span class="text-emerald-500">PRO</span></h1>
42
+ <p class="text-center text-slate-400 text-sm mb-8">Anti-Shake + Audio Preserved + Border Fill</p>
43
 
44
  <form id="uploadForm" class="space-y-6">
45
  <div class="group relative border-2 border-dashed border-slate-200 rounded-2xl p-8 text-center hover:border-indigo-400 transition-colors">
 
69
  <div id="status" class="mt-8 hidden">
70
  <div class="flex flex-col items-center justify-center space-y-4">
71
  <div class="loader ease-linear rounded-full border-4 border-t-4 border-slate-200 h-12 w-12"></div>
72
+ <p class="text-indigo-600 font-bold text-sm animate-pulse text-center">
73
+ AI sedang bekerja...<br>
74
+ <span class="text-[10px] text-slate-400">Menghilangkan guncangan, mengisi border & menyatukan audio</span>
75
+ </p>
76
  </div>
77
  </div>
78
 
 
138
  async def stabilize_video(file: UploadFile = File(None), url: str = Form(None)):
139
  job_id = str(uuid.uuid4())
140
  input_path = os.path.join(UPLOAD_DIR, f"{job_id}_in.mp4")
 
 
 
141
  raw_output_path = os.path.join(OUTPUT_DIR, f"{job_id}_raw.avi")
142
  final_output_path = os.path.join(OUTPUT_DIR, f"{job_id}_final.mp4")
143
 
144
  try:
145
+ # 1. Simpan Input Video
146
  if file:
147
  with open(input_path, "wb") as buffer:
148
  shutil.copyfileobj(file.file, buffer)
 
156
 
157
  # 2. Proses Stabilisasi (VidStab)
158
  stabilizer = VidStab()
159
+
160
+ # PERBAIKAN KUALITAS:
161
+ # - smoothing_window=30 : Membuat gerakan kamera jauh lebih mulus (seperti pakai gimbal).
162
+ # - border_type='replicate' : Menghilangkan kotak/border hitam dengan cara mereplikasi pixel terluar.
163
+ stabilizer.stabilize(
164
+ input_path=input_path,
165
+ output_path=raw_output_path,
166
+ smoothing_window=30,
167
+ border_type='replicate',
168
+ playback=False
169
+ )
170
+
171
+ # 3. Konversi + GABUNGKAN AUDIO (Audio Muxing)
172
+ # Mengambil Video dari file .avi (hasil stabil) dan Audio dari file .mp4 (video asli)
173
  ffmpeg_cmd = [
174
+ 'ffmpeg', '-y',
175
+ '-i', raw_output_path, # Input 0: Video Stabil (Tidak bersuara)
176
+ '-i', input_path, # Input 1: Video Asli (Bersuara)
177
+ '-map', '0:v:0', # Ambil track Video dari Input 0
178
+ '-map', '1:a:0?', # Ambil track Audio dari Input 1 (tanda '?' = abaikan jika video asli memang bisu)
179
+ '-c:v', 'libx264', # Codec Video
180
+ '-preset', 'fast', # Kecepatan render sedikit lebih baik
181
+ '-crf', '23', # Kualitas visual ditingkatkan (semakin kecil = semakin jernih)
182
+ '-pix_fmt', 'yuv420p',
183
+ '-c:a', 'aac', # Codec Audio
184
+ '-b:a', '128k', # Bitrate Audio
185
+ '-movflags', '+faststart',
186
  final_output_path
187
  ]
188
+
189
+ # Jalankan FFmpeg
190
  subprocess.run(ffmpeg_cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
191
 
192
  # 4. Cleanup file sementara