wa / app.py
Kompres's picture
Upload app.py
9afffa5 verified
Raw History Blame Contribute Delete
7.47 kB
import gradio as gr
import ffmpeg
import os
import tempfile
import subprocess
import re
from pathlib import Path
def get_video_info(input_path):
"""Ambil informasi video"""
try:
probe = ffmpeg.probe(input_path)
video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
return video_info
except:
return None
def compress_video(input_video, quality_preset, progress=gr.Progress()):
"""Kompres video dengan kualitas terjaga tapi ukuran super kecil"""
if input_video is None:
return None, "Silakan upload video terlebih dahulu"
try:
progress(0, desc="Memulai proses...")
# Buat file temporary untuk output
output_path = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4').name
progress(0.1, desc="Membaca informasi video...")
# Dapatkan info video
video_info = get_video_info(input_video)
if not video_info:
return None, "Gagal membaca informasi video"
original_size = os.path.getsize(input_video) / (1024 * 1024) # MB
# Dapatkan durasi video
duration = float(video_info.get('duration', 0))
if duration == 0:
probe = ffmpeg.probe(input_video)
duration = float(probe['format']['duration'])
progress(0.2, desc="Menghitung parameter optimal...")
# Target ukuran berdasarkan preset (dalam MB)
# Naikin target size biar kualitas tetap bagus
target_sizes = {
"Kualitas Maksimal (ukuran lebih besar)": min(original_size * 0.4, 3.0), # Max 3MB
"Seimbang (recommended)": min(original_size * 0.3, 2.0), # Max 2MB
"Ukuran Kecil (kualitas masih bagus)": min(original_size * 0.25, 1.5) # Max 1.5MB
}
target_size_mb = target_sizes.get(quality_preset, 2.0)
# Hitung target bitrate (dalam kbps)
audio_bitrate = 128 # kbps - naikin lagi ke 128
target_bitrate = int((target_size_mb * 8192) / duration) - audio_bitrate
target_bitrate = max(target_bitrate, 800) # Minimal 800kbps biar gak burik
progress(0.25, desc="Memulai encoding video...")
# Parameter x264 yang dioptimasi untuk kualitas visual
x264_params = [
'ref=5', # Lebih banyak reference frames
'bframes=4', # Lebih banyak B-frames
'b-adapt=2',
'direct=auto',
'me=umh',
'subme=10', # Naikin subpixel ME untuk detail lebih baik
'trellis=2',
'aq-mode=3',
'aq-strength=1.0', # Naikin AQ strength
'psy-rd=1.0:0.2', # Lebih fokus ke psychovisual
'deblock=0:0', # Deblocking normal biar gak burik
'fast-pskip=0', # Matiin fast skip biar lebih detail
'mixed-refs=1',
'rc-lookahead=60', # Lebih banyak lookahead
'mbtree=1',
'qcomp=0.6', # Quantizer compression
'qpmin=10', # Minimal QP biar gak terlalu compress
'qpmax=51',
]
# Build command ffmpeg
cmd = [
'ffmpeg',
'-i', input_video,
'-vcodec', 'libx264',
'-b:v', f'{target_bitrate}k',
'-maxrate', f'{int(target_bitrate * 1.3)}k', # Turunin maxrate multiplier
'-bufsize', f'{int(target_bitrate * 2)}k',
'-preset', 'slow', # Ganti ke slow (veryslow terlalu lama)
'-profile:v', 'high', # Profile high untuk kualitas lebih baik
'-level', '4.1',
'-acodec', 'aac',
'-b:a', f'{audio_bitrate}k',
'-pix_fmt', 'yuv420p',
'-movflags', 'faststart',
'-x264-params', ':'.join(x264_params),
'-y',
output_path
]
# Jalankan ffmpeg dengan progress tracking
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
# Track progress dari stderr ffmpeg
for line in process.stderr:
# Parse time dari output ffmpeg
time_match = re.search(r'time=(\d{2}):(\d{2}):(\d{2}\.\d{2})', line)
if time_match:
hours = int(time_match.group(1))
minutes = int(time_match.group(2))
seconds = float(time_match.group(3))
current_time = hours * 3600 + minutes * 60 + seconds
# Hitung progress (25% sampai 95%)
if duration > 0:
encode_progress = min(current_time / duration, 1.0)
total_progress = 0.25 + (encode_progress * 0.7)
progress(total_progress, desc=f"Encoding video... {int(encode_progress * 100)}%")
process.wait()
if process.returncode != 0:
raise Exception("FFmpeg encoding gagal")
progress(0.95, desc="Finalisasi...")
# Hitung hasil kompresi
compressed_size = os.path.getsize(output_path) / (1024 * 1024)
reduction = ((original_size - compressed_size) / original_size) * 100
progress(1.0, desc="Selesai!")
result_text = f"""
✅ Konversi berhasil!
📊 Hasil:
• Ukuran awal: {original_size:.2f} MB
• Ukuran akhir: {compressed_size:.2f} MB
• Pengurangan: {reduction:.1f}%
• Target bitrate: {target_bitrate} kbps
• Codec: H.264 (optimized)
Video sudah dikompres maksimal dengan tetap menjaga kualitas visual HD.
"""
return output_path, result_text
except Exception as e:
error_msg = str(e)
return None, f"Terjadi kesalahan: {error_msg}"
# Buat interface
with gr.Blocks() as demo:
gr.Markdown("""
# Video Optimizer
Kompres video kamu tanpa mengurangi kualitas. Cocok untuk kirim via WhatsApp atau media sosial lainnya.
""")
with gr.Row():
with gr.Column():
input_video = gr.Video(label="Upload Video")
quality_preset = gr.Radio(
choices=[
"Kualitas Maksimal (ukuran lebih besar)",
"Seimbang (recommended)",
"Ukuran Kecil (kualitas masih bagus)"
],
value="Seimbang (recommended)",
label="Pilih Preset"
)
compress_btn = gr.Button("Proses Video", variant="primary")
with gr.Column():
output_video = gr.Video(label="Video Hasil")
result_text = gr.Textbox(label="Status", lines=8)
compress_btn.click(
fn=compress_video,
inputs=[input_video, quality_preset],
outputs=[output_video, result_text]
)
gr.Markdown("""
### Tips:
- Gunakan preset "Seimbang" untuk hasil optimal
- Video akan dikonversi ke format H.265 yang lebih efisien
- Kualitas warna dan detail akan tetap terjaga
""")
if __name__ == "__main__":
demo.queue()
demo.launch(server_name="0.0.0.0", server_port=7860, share=False)