En este momento estás viendo Cómo crear un compresor de video en Python para estados de Whatsapp

Cómo crear un compresor de video en Python para estados de Whatsapp

Tiempo de lectura estimado: 3 minutos

¿Estás harto de herramientas online lentas y limitadas? ¡Aquí tienes una app en Python con GUI que comprime cualquier video a exactamente 10 MB! Ideal para compartir en WhatsApp, emails, formularios, etc. 💥

Características de la app

  • Comprime cualquier video .mp4, .mov, .avi, .mkv a un tamaño máximo de 10 MB.
  • Estima el bitrate óptimo automáticamente.
  • Interfaz gráfica en pantalla completa con barra de progreso 🔥
  • Muestra el nombre, tamaño original y tamaño final del video.
  • Reproduce un sonido de éxito o error.

 

¿Cómo funciona?

Usamos ffmpeg y ffprobe para analizar la duración del video, calcular el bitrate exacto necesario, y luego lo comprimimos con esa calidad de video más un bitrate de audio fijo de 128 kbps.

 

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import subprocess
import os
import threading
import re
import winsound

TAMANIO_MAX_MB = 10
BITRATE_AUDIO = 128000

def reproducir_sonido(tipo="ok"):
    try:
        if tipo == "ok":
            winsound.Beep(1000, 500)
        else:
            winsound.Beep(500, 500)
    except Exception as e:
        print(f"🔇 Error al reproducir el sonido: {e}")

def comprimir_10mb():
    ruta_video = filedialog.askopenfilename(filetypes=[("Videos", "*.mp4 *.mov *.avi *.mkv")])
    if not ruta_video:
        return

    carpeta_salida = filedialog.askdirectory()
    if not carpeta_salida:
        return

    def proceso_compresion():
        try:
            peso_original = os.path.getsize(ruta_video) / (1024 * 1024)
            archivo_origen_label.config(text=f"📦 Archivo original: {ruta_video}")
            tamaño_origen_label.config(text=f"📏 Tamaño original: {peso_original:.2f} MB")

            update_estado("🔍 Obteniendo duración del video...")
            comando_duracion = [
                "ffprobe", "-v", "error", "-show_entries",
                "format=duration", "-of",
                "default=noprint_wrappers=1:nokey=1", ruta_video
            ]
            duracion_segundos = float(subprocess.check_output(comando_duracion).decode().strip())

            bits_totales = TAMANIO_MAX_MB * 8 * 1024 * 1024
            bitrate_total = bits_totales / duracion_segundos
            bitrate_video = int(bitrate_total - BITRATE_AUDIO)
            if bitrate_video < 100000:
                bitrate_video = 100000

            nombre_archivo = os.path.splitext(os.path.basename(ruta_video))[0]
            salida = os.path.join(carpeta_salida, f"{nombre_archivo}_10MB.mp4")

            comando = [
                "ffmpeg", "-i", ruta_video,
                "-b:v", str(bitrate_video),
                "-b:a", "128k",
                "-preset", "slow",
                "-y", salida
            ]

            update_estado("🚀 Iniciando compresión...")
            progreso["maximum"] = duracion_segundos
            progreso["value"] = 0

            proceso = subprocess.Popen(comando, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
            for linea in proceso.stdout:
                ventana.update()
                tiempo_match = re.search(r"time=(\d+):(\d+):(\d+.\d+)", linea)
                if tiempo_match:
                    h, m, s = tiempo_match.groups()
                    tiempo_actual = int(h) * 3600 + int(m) * 60 + float(s)
                    progreso["value"] = tiempo_actual
                    porcentaje = min(100, (tiempo_actual / duracion_segundos) * 100)
                    update_estado(f"⏳ Progreso: {porcentaje:.1f}%")

            proceso.wait()
            progreso["value"] = duracion_segundos
            update_estado("✅ ¡Compresión completada!")

            if os.path.exists(salida):
                peso_final = os.path.getsize(salida) / (1024 * 1024)
                archivo_salida_label.config(text=f"📁 Archivo comprimido: {salida}")
                tamaño_final_label.config(text=f"📉 Tamaño final: {peso_final:.2f} MB")
                if peso_final <= TAMANIO_MAX_MB:
                    reproducir_sonido("ok")
                    messagebox.showinfo("✅ ¡Listo!", f"Video comprimido a {peso_final:.2f} MB:\n{salida}")
                else:
                    reproducir_sonido("error")
                    messagebox.showwarning("⚠️ Casi", f"Pesa {peso_final:.2f} MB (ligeramente más de 10 MB)")
            else:
                reproducir_sonido("error")
                messagebox.showerror("❌ Error", "No se generó el archivo.")
        except Exception as e:
            reproducir_sonido("error")
            update_estado("❌ Error durante la compresión.")
            messagebox.showerror("Error", f"Algo falló:\n{str(e)}")

    threading.Thread(target=proceso_compresion).start()

def update_estado(mensaje):
    progreso_label.config(text=mensaje)
    ventana.update()

ventana = tk.Tk()
ventana.title("🔥 Compresor Exacto a 10MB 🔥")
ventana.attributes('-fullscreen', True)

frame = tk.Frame(ventana, bg="#1e1e1e")
frame.pack(expand=True, fill="both")

titulo = tk.Label(frame, text="🎥 Compresor de Video a 10MB", font=("Helvetica", 32, "bold"), fg="white", bg="#1e1e1e")
titulo.pack(pady=(40, 20))

subtexto = tk.Label(frame, text="Selecciona un video y lo comprimimos al máximo: 10 MB",
                    font=("Helvetica", 18), fg="#bbbbbb", bg="#1e1e1e")
subtexto.pack(pady=(0, 40))

btn = tk.Button(frame, text="📁 Seleccionar Video y Comprimir", font=("Helvetica", 20),
                bg="#00cc66", fg="white", activebackground="#00994d", command=comprimir_10mb)
btn.pack(pady=10, ipadx=20, ipady=10)

progreso_label = tk.Label(frame, text="", font=("Helvetica", 18), fg="white", bg="#1e1e1e")
progreso_label.pack(pady=(30, 10))

progreso = ttk.Progressbar(frame, mode="determinate", length=700)
progreso.pack(pady=10)

archivo_origen_label = tk.Label(frame, text="📦 Archivo original: ", font=("Helvetica", 14), fg="white", bg="#1e1e1e")
archivo_origen_label.pack(pady=(10, 5))

tamaño_origen_label = tk.Label(frame, text="📏 Tamaño original: ", font=("Helvetica", 14), fg="white", bg="#1e1e1e")
tamaño_origen_label.pack(pady=(0, 10))

archivo_salida_label = tk.Label(frame, text="📁 Archivo comprimido: ", font=("Helvetica", 14), fg="white", bg="#1e1e1e")
archivo_salida_label.pack(pady=(10, 5))

tamaño_final_label = tk.Label(frame, text="📉 Tamaño final: ", font=("Helvetica", 14), fg="white", bg="#1e1e1e")
tamaño_final_label.pack(pady=(0, 10))

btn_salir = tk.Button(frame, text="❌ Salir", font=("Helvetica", 16),
                      bg="#ff3333", fg="white", activebackground="#cc0000", command=ventana.destroy)
btn_salir.pack(side="bottom", pady=30)

ventana.mainloop()

 

¿Qué necesitas para que funcione?

  • Python 3 instalado
  • Instalar ffmpeg en el sistema (disponible para Windows/macOS/Linux)
  • Tener el módulo tkinter, que viene incluido con Python

Recomendado: empaquetar como .exe

Puedes convertir esta app en un .exe con pyinstaller para que cualquier persona sin Python lo use:

pyinstaller --onefile --noconsole --add-data "*.mp3;." compresor.py

 

 

 


Serna Studio

Desarrollador de software • Amante del diseño gráfico, diseño 3D y la locura • 🧠 + 🙌 + ☕️ son los ingredientes que debemos unir • ¡No pongas fronteras en tus proyectos!.

Deja una respuesta