|
|
import gradio as gr |
|
|
import os |
|
|
import shutil |
|
|
import subprocess |
|
|
import time |
|
|
from datetime import datetime, timedelta |
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
def process_video(fileobj): |
|
|
|
|
|
UPLOAD_FOLDER = "/tmp/uploads" |
|
|
OUTPUT_FOLDER = "/tmp/outputs" |
|
|
PROGRESS_FILE = "/tmp/progress.txt" |
|
|
|
|
|
|
|
|
for folder in [UPLOAD_FOLDER, OUTPUT_FOLDER]: |
|
|
if not os.path.exists(folder): |
|
|
os.makedirs(folder) |
|
|
|
|
|
|
|
|
input_path = os.path.join(UPLOAD_FOLDER, os.path.basename(fileobj.name)) |
|
|
shutil.copyfile(fileobj.name, input_path) |
|
|
|
|
|
|
|
|
output_filename = "output_video.mp4" |
|
|
output_path = os.path.join(OUTPUT_FOLDER, output_filename) |
|
|
|
|
|
|
|
|
duration = get_video_duration(input_path) |
|
|
if duration == 0: |
|
|
|
|
|
yield f"Peringatan: Tidak dapat membaca durasi video. Progres tidak akan ditampilkan.", None, None |
|
|
duration = float("inf") |
|
|
|
|
|
|
|
|
ffmpeg_cmd = [ |
|
|
"ffmpeg", |
|
|
"-y", |
|
|
"-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: |
|
|
|
|
|
process = subprocess.Popen(ffmpeg_cmd, stderr=subprocess.PIPE, universal_newlines=True) |
|
|
|
|
|
start_time = time.time() |
|
|
progress_percent = 0 |
|
|
eta = "Menghitung..." |
|
|
|
|
|
|
|
|
while process.poll() is None: |
|
|
if duration == float("inf"): |
|
|
|
|
|
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 |
|
|
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) |
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
for file_path in [input_path, PROGRESS_FILE]: |
|
|
if os.path.exists(file_path): |
|
|
os.remove(file_path) |
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
upload_button.upload( |
|
|
process_video, |
|
|
inputs=upload_button, |
|
|
outputs=[progress_text, preview, download_button] |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |