import gradio as gr import os import shutil import subprocess import time from datetime import datetime, timedelta # Fungsi untuk mendapatkan durasi video def get_video_duration(input_path): cmd = [ "ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", input_path ] try: result = subprocess.run(cmd, capture_output=True, text=True, check=True) duration = float(result.stdout.strip()) if duration <= 0: raise ValueError("Durasi video tidak valid atau nol.") return duration except (subprocess.CalledProcessError, ValueError) as e: # Log error untuk debugging error_msg = f"Gagal mendapatkan durasi: {str(e)}\nSTDERR: {result.stderr if 'result' in locals() else 'Tidak ada output'}" with open("/tmp/ffprobe_error.log", "w") as f: f.write(error_msg) return 0 # Fallback ke 0 jika gagal # Fungsi untuk memproses video dengan FFmpeg dan memantau progres def process_video(fileobj): # Direktori untuk menyimpan file UPLOAD_FOLDER = "/tmp/uploads" OUTPUT_FOLDER = "/tmp/outputs" PROGRESS_FILE = "/tmp/progress.txt" # Buat direktori jika belum ada for folder in [UPLOAD_FOLDER, OUTPUT_FOLDER]: if not os.path.exists(folder): os.makedirs(folder) # Simpan file yang diunggah input_path = os.path.join(UPLOAD_FOLDER, os.path.basename(fileobj.name)) shutil.copyfile(fileobj.name, input_path) # Path untuk file output output_filename = "output_video.mp4" output_path = os.path.join(OUTPUT_FOLDER, output_filename) # Dapatkan durasi video duration = get_video_duration(input_path) if duration == 0: # Fallback: Lanjutkan tanpa durasi, progres tidak akan akurat yield f"Peringatan: Tidak dapat membaca durasi video. Progres tidak akan ditampilkan.", None, None duration = float("inf") # Hindari pembagian nol # Perintah FFmpeg untuk frame interpolation ffmpeg_cmd = [ "ffmpeg", "-y", # Overwrite file output "-i", input_path, "-vf", "minterpolate=fps=60:mi_mode=mci:mc_mode=aobmc:vsbmc=1:me_mode=bidir", "-c:v", "libx264", "-preset", "fast", "-c:a", "copy", "-progress", PROGRESS_FILE, output_path ] try: # Jalankan FFmpeg sebagai proses terpisah process = subprocess.Popen(ffmpeg_cmd, stderr=subprocess.PIPE, universal_newlines=True) start_time = time.time() progress_percent = 0 eta = "Menghitung..." # Pantau progres secara real-time while process.poll() is None: if duration == float("inf"): # Jika durasi tidak tersedia, tampilkan progres tanpa persentase elapsed_time = time.time() - start_time yield f"Progres: Sedang memproses... | Waktu Berjalan: {str(timedelta(seconds=int(elapsed_time)))}", None, None elif os.path.exists(PROGRESS_FILE): with open(PROGRESS_FILE, "r") as f: lines = f.readlines() for line in lines: if "out_time_ms=" in line: out_time_ms = float(line.split("=")[1]) / 1_000_000 # Konversi ke detik progress_percent = min((out_time_ms / duration) * 100, 100) elapsed_time = time.time() - start_time if progress_percent > 0: total_estimated_time = elapsed_time / (progress_percent / 100) eta_seconds = total_estimated_time - elapsed_time eta = str(timedelta(seconds=int(eta_seconds))) else: eta = "Menghitung..." yield f"Progres: {progress_percent:.1f}% | Estimasi Selesai: {eta}", None, None time.sleep(1) # Jeda untuk mengurangi beban CPU # Periksa apakah proses berhasil if process.returncode == 0: yield f"Progres: 100% | Selesai!", output_path, output_path else: stderr_output = process.communicate()[1] yield f"Error FFmpeg: {stderr_output}", None, None except Exception as e: yield f"Error: {str(e)}", None, None finally: # Bersihkan file sementara for file_path in [input_path, PROGRESS_FILE]: if os.path.exists(file_path): os.remove(file_path) # Antarmuka Gradio with gr.Blocks() as demo: gr.Markdown("# Frame Interpolation dengan FFmpeg") gr.Markdown("Unggah video untuk meningkatkan frame rate menjadi 60 FPS menggunakan FFmpeg.") with gr.Row(): with gr.Column(): upload_button = gr.UploadButton( "Unggah Video", file_types=["video"], file_count="single" ) with gr.Column(): progress_text = gr.Textbox(label="Status Proses") preview = gr.Video(label="Preview Video Hasil") download_button = gr.File(label="Unduh Video Hasil") # Hubungkan upload dengan fungsi pemrosesan upload_button.upload( process_video, inputs=upload_button, outputs=[progress_text, preview, download_button] ) # Jalankan aplikasi if __name__ == "__main__": demo.launch()