Compresión Automática de Vídeos a 10 MB con Python y FFmpeg
¿Necesitas reducir un vídeo para poder enviarlo mediante una plataforma que impone un límite de tamaño? Con Python y FFmpeg podemos construir una aplicación de escritorio capaz de analizar un vídeo, calcular automáticamente un bitrate objetivo y generar una versión comprimida intentando mantener el archivo por debajo de un límite determinado.
En este proyecto vamos a construir un pequeño compresor de vídeo con interfaz gráfica mediante Tkinter. La aplicación permite seleccionar un archivo de vídeo, analizar su duración mediante FFprobe, calcular el bitrate disponible y ejecutar FFmpeg para generar una versión comprimida.
El objetivo práctico es trabajar con un límite de aproximadamente 10 MB, pero antes de entrar en el código hay que aclarar algo importante desde el punto de vista técnico:
el programa no puede garantizar que el archivo resultante tenga exactamente 10 MB. El algoritmo calcula un bitrate objetivo basándose en la duración y en un presupuesto de bits, pero el tamaño final depende también del audio, el contenedor, los metadatos y otros factores de la codificación.
Por tanto, el objetivo real de esta versión es intentar generar un archivo de 10 MB como máximo y comprobar posteriormente el tamaño obtenido.
¿Qué hace la aplicación?
El funcionamiento completo puede resumirse en una cadena de procesamiento bastante sencilla:
- El usuario selecciona un vídeo.
- La aplicación obtiene el tamaño original.
ffprobeanaliza el archivo.- Se obtiene la duración del vídeo.
- Se calcula el presupuesto total de bits.
- Se reserva una cantidad determinada para el audio.
- El resto del presupuesto se asigna al vídeo.
- FFmpeg realiza la codificación.
- La aplicación monitoriza el progreso.
- Finalmente se comprueba el tamaño real del archivo generado.
Podemos representarlo de la siguiente manera:
VÍDEO ORIGINAL
│
▼
FFPROBE
│
├──► Duración
│
▼
CÁLCULO DE BITRATE
│
├──► Presupuesto total
├──► Bitrate de audio
└──► Bitrate de vídeo
│
▼
FFMPEG
│
▼
VÍDEO COMPRIMIDO
│
▼
COMPROBACIÓN DEL TAMAÑO FINAL
La ventaja de separar el análisis de la codificación es que Python no tiene que implementar ningún codec de vídeo. La aplicación actúa como una capa de control sobre las herramientas multimedia proporcionadas por FFmpeg.
10 MB no significa exactamente 10 MB
El título de este proyecto puede resultar tentador: “comprimir cualquier vídeo a exactamente 10 MB”. Sin embargo, desde un punto de vista técnico, esa afirmación necesita una matización.
El tamaño final de un archivo multimedia depende de múltiples variables:
- Duración del vídeo.
- Bitrate de vídeo.
- Bitrate de audio.
- Codec utilizado.
- Contenedor utilizado.
- Metadatos.
- Configuración del encoder.
- Overhead del contenedor.
- Características del propio contenido.
Por esta razón, calcular:
tamaño ÷ duración = bitrate
proporciona una estimación muy útil, pero no una garantía matemática del tamaño final.
La estrategia utilizada en este proyecto es, por tanto:
1. Calcular un bitrate objetivo. 2. Codificar el vídeo. 3. Medir el archivo resultante. 4. Comprobar si cumple el límite.
Una aplicación profesional podría ir todavía más lejos y repetir automáticamente el proceso cuando el resultado supere el límite.
¿Por qué utilizar FFmpeg y FFprobe?
FFmpeg es una de las herramientas más utilizadas para procesamiento y conversión de contenido multimedia. Permite trabajar con vídeo, audio, codecs, contenedores, filtros y múltiples formatos.
FFprobe forma parte del mismo ecosistema y está especializado en obtener información técnica de archivos multimedia.
En nuestra aplicación cada herramienta tiene una función distinta:
| Herramienta | Función |
|---|---|
| Python | Lógica de la aplicación e interfaz gráfica |
| FFprobe | Análisis del archivo multimedia |
| FFmpeg | Codificación y compresión |
| Tkinter | Interfaz gráfica |
La arquitectura queda aproximadamente así:
┌─────────────────┐
│ TKINTER │
│ Interfaz GUI │
└────────┬────────┘
│
▼
┌─────────────────┐
│ PYTHON │
│ Lógica/control │
└───────┬─┬───────┘
│ │
┌──────────┘ └──────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ FFPROBE │ │ FFMPEG │
│ Análisis │ │ Codificación│
└─────────────┘ └──────┬──────┘
│
▼
┌─────────────┐
│ MP4 FINAL │
└─────────────┘
Cálculo del bitrate
Esta es probablemente la parte más interesante del proyecto desde el punto de vista matemático.
Tenemos un límite de tamaño:
TAMANIO_MAX_MB = 10
Y un bitrate de audio:
BITRATE_AUDIO = 128000
Los 128000 bits por segundo equivalen a:
128 kbps
Primero calculamos cuántos bits contiene el presupuesto total:
bits_totales = TAMANIO_MAX_MB * 8 * 1024 * 1024
Después dividimos ese presupuesto entre la duración:
bitrate_total = bits_totales / duracion_segundos
Este bitrate representa aproximadamente la cantidad total de bits por segundo que podemos utilizar entre vídeo y audio.
Como hemos reservado 128 kbps para el audio, restamos esa cantidad:
bitrate_video = int(
bitrate_total - BITRATE_AUDIO
)
De esta forma obtenemos el bitrate disponible para el flujo de vídeo.
Un ejemplo sencillo
Supongamos un vídeo de 60 segundos.
Tenemos aproximadamente:
10 MB ↓ 80 megabits aproximadamente ↓ 80 / 60 ↓ ≈ 1,33 Mbps de bitrate total
Si reservamos:
128 kbps para audio
el bitrate disponible para vídeo será aproximadamente:
1,33 Mbps - 0,128 Mbps ≈ 1,20 Mbps
En cambio, si el vídeo durase 10 minutos, el mismo presupuesto tendría que repartirse entre muchos más segundos, por lo que el bitrate disponible sería considerablemente menor.
Esta es precisamente la razón por la que la duración del vídeo es fundamental para calcular el bitrate objetivo.
Obtención de la duración mediante FFprobe
El programa construye el siguiente comando:
comando_duracion = [
"ffprobe",
"-v",
"error",
"-show_entries",
"format=duration",
"-of",
"default=noprint_wrappers=1:nokey=1",
ruta_video
]
La opción -v error limita la salida a errores.
-show_entries format=duration solicita específicamente la duración del contenedor.
Y:
-of default=noprint_wrappers=1:nokey=1
hace que FFprobe devuelva únicamente el valor que nos interesa, evitando información adicional.
Python ejecuta el proceso mediante subprocess:
duracion_segundos = float(
subprocess.check_output(
comando_duracion
).decode().strip()
)
El resultado se convierte en un número de coma flotante porque la duración puede contener fracciones de segundo.
Codificación con FFmpeg
Una vez calculado el bitrate objetivo, construimos el comando de FFmpeg:
comando = [
"ffmpeg",
"-i",
ruta_video,
"-b:v",
str(bitrate_video),
"-b:a",
"128k",
"-preset",
"slow",
"-y",
salida
]
Vamos a analizar los parámetros importantes.
-i
Indica el archivo de entrada:
-i video_original.mp4
-b:v
Define el bitrate objetivo del vídeo:
-b:v 1200000
El valor está expresado en bits por segundo.
-b:a
Establece el bitrate del audio:
-b:a 128k
En este ejemplo reservamos 128 kbps para el audio.
-preset slow
El preset controla diferentes decisiones internas del encoder. slow utiliza más tiempo de procesamiento que presets más rápidos, pero puede conseguir una codificación más eficiente.
Es importante entender que slow no significa simplemente “más calidad”. El resultado depende también del bitrate, codec, resolución y demás parámetros del encoder.
-y
Permite sobrescribir automáticamente el archivo de salida si ya existe.
Seguimiento del progreso
La aplicación ejecuta FFmpeg mediante:
proceso = subprocess.Popen(
comando,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True
)
FFmpeg proporciona información sobre el tiempo de vídeo que ya ha procesado.
El programa busca esa información mediante una expresión regular:
tiempo_match = re.search(
r"time=(\d+):(\d+):(\d+.\d+)",
linea
)
Después convierte horas, minutos y segundos a segundos:
h, m, s = tiempo_match.groups()
tiempo_actual = (
int(h) * 3600 +
int(m) * 60 +
float(s)
)
Y calcula el porcentaje:
porcentaje = min(
100,
(tiempo_actual / duracion_segundos) * 100
)
Por tanto, la barra de progreso representa el tiempo de vídeo procesado, no el porcentaje exacto del tamaño final del archivo.
Interfaz gráfica con Tkinter
La interfaz está construida utilizando Tkinter, una biblioteca gráfica que forma parte del ecosistema estándar de Python y que resulta especialmente apropiada para herramientas de escritorio sencillas.
La aplicación crea una ventana:
ventana = tk.Tk()
ventana.title(
"🔥 Compresor Exacto a 10MB 🔥"
)
Y la coloca en pantalla completa:
ventana.attributes(
'-fullscreen',
True
)
La interfaz contiene:
- Título de la aplicación.
- Descripción del funcionamiento.
- Selector de archivos.
- Barra de progreso.
- Información del archivo original.
- Información del archivo resultante.
- Tamaño original.
- Tamaño final.
- Botón para cerrar la aplicación.
Selección del vídeo
El selector utiliza:
ruta_video = filedialog.askopenfilename(
filetypes=[
("Videos", "*.mp4 *.mov *.avi *.mkv")
]
)
De esta manera el usuario puede seleccionar formatos habituales como:
MP4MOVAVIMKV
Hay que recordar que la extensión del archivo no determina por sí sola si FFmpeg podrá procesarlo. Lo importante es que el contenedor y los codecs utilizados sean compatibles con la instalación de FFmpeg.
Selección de la carpeta de salida
Una vez seleccionado el vídeo, el programa solicita dónde guardar el resultado:
carpeta_salida = filedialog.askdirectory()
if not carpeta_salida:
return
El nombre de salida se construye automáticamente:
nombre_archivo = os.path.splitext(
os.path.basename(ruta_video)
)[0]
salida = os.path.join(
carpeta_salida,
f"{nombre_archivo}_10MB.mp4"
)
Por ejemplo:
vacaciones.mov
↓
vacaciones_10MB.mp4
Procesamiento en segundo plano
La compresión de vídeo puede consumir bastante CPU y tardar varios minutos. Para evitar que la operación se ejecute directamente dentro del callback de la interfaz, el programa utiliza un hilo:
threading.Thread(
target=proceso_compresion
).start()
La idea es correcta: el trabajo pesado no debería ejecutarse directamente en el hilo principal de Tkinter.
Sin embargo, existe una consideración técnica importante.
Tkinter no está diseñado para que sus widgets sean modificados directamente desde hilos secundarios.
El código original realiza operaciones como:
progreso["value"] = tiempo_actual archivo_origen_label.config(...) update_estado(...) messagebox.showinfo(...)
desde el hilo de compresión.
En una aplicación más robusta sería preferible utilizar after() o una estructura como queue.Queue para enviar información desde el worker al hilo principal.
Esto es especialmente importante cuando la aplicación se utiliza durante largos periodos o cuando se ejecutan varias operaciones consecutivas.
Comprobación del tamaño final
Una de las partes más importantes del programa se ejecuta una vez terminada la codificación.
Primero se comprueba que el archivo exista:
if os.path.exists(salida):
Después se obtiene su tamaño:
peso_final = (
os.path.getsize(salida) /
(1024 * 1024)
)
Y finalmente se compara con el límite:
if peso_final <= TAMANIO_MAX_MB:
reproducir_sonido("ok")
else:
reproducir_sonido("error")
Esta comprobación es fundamental porque el bitrate calculado inicialmente es solamente una estimación.
¿Qué ocurre si el archivo supera los 10 MB?
La versión actual muestra una advertencia:
messagebox.showwarning(
"⚠️ Casi",
f"Pesa {peso_final:.2f} MB "
f"(ligeramente más de 10 MB)"
)
Pero no realiza una segunda compresión.
Una versión más avanzada podría implementar un algoritmo iterativo:
Calcular bitrate
│
▼
Codificar
│
▼
Medir tamaño
│
├──► ≤ 10 MB ──► FIN
│
└──► > 10 MB
│
▼
Reducir bitrate
│
▼
Codificar
│
└──────────► repetir
Este enfoque permitiría acercarse mucho más al límite deseado de forma automática.
Sonidos de éxito y error
La aplicación utiliza winsound para generar una señal sonora:
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}"
)
La frecuencia utilizada permite diferenciar visual y acústicamente una operación correcta de una operación que ha terminado con error.
Hay que tener en cuenta que winsound es específico de Windows. Por tanto, esta parte del código no es portable directamente a macOS o Linux.
Código fuente completo
A continuación se muestra el código completo de la aplicación:
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: "
f"{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: "
f"{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: "
f"{salida}"
)
)
tamaño_final_label.config(
text=(
f"📉 Tamaño final: "
f"{peso_final:.2f} MB"
)
)
if peso_final <= TAMANIO_MAX_MB:
reproducir_sonido("ok")
messagebox.showinfo(
"✅ ¡Listo!",
(
f"Video comprimido a "
f"{peso_final:.2f} MB:\n"
f"{salida}"
)
)
else:
reproducir_sonido("error")
messagebox.showwarning(
"⚠️ Casi",
(
f"Pesa {peso_final:.2f} MB "
f"(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é necesitamos para ejecutar el programa?
La aplicación tiene muy pocas dependencias Python porque gran parte del trabajo se delega a FFmpeg.
- Python 3.
- Tkinter.
- FFmpeg.
- FFprobe.
En Windows, Tkinter suele venir incluido en las instalaciones estándar de Python.
Podemos comprobarlo ejecutando:
python -m tkinter
Si se abre la ventana de prueba de Tkinter, el módulo está disponible.
Comprobar FFmpeg y FFprobe
La aplicación ejecuta directamente los comandos:
ffmpeg ffprobe
Por tanto, ambos programas deben estar disponibles desde el PATH del sistema.
Podemos comprobarlo desde PowerShell:
ffmpeg -version ffprobe -version
Si ambos comandos muestran la información de versión, Python podrá encontrarlos mediante subprocess.
Si aparece un mensaje indicando que el comando no existe, será necesario instalar FFmpeg y añadir su directorio de binarios al PATH.
Instalación de FFmpeg
FFmpeg no es una biblioteca Python convencional que podamos instalar simplemente con pip. Es un conjunto de herramientas multimedia independientes que debe estar disponible en el sistema.
La aplicación depende concretamente de:
ffmpeg.exe ffprobe.exe
en Windows.
En macOS y Linux el nombre de los ejecutables normalmente será:
ffmpeg ffprobe
Empaquetar la aplicación como .exe
Una vez que el programa funciona correctamente desde Python, podemos empaquetarlo utilizando PyInstaller.
Primero instalamos PyInstaller:
pip install pyinstaller
Y posteriormente:
pyinstaller --onefile --noconsole compresor.py
El ejecutable generado aparecerá normalmente en:
dist/ └── compresor.exe
Sin embargo, hay una cuestión importante: PyInstaller no incluye automáticamente FFmpeg porque nuestro programa lo está ejecutando como un proceso externo.
Si queremos distribuir un .exe completamente independiente, tendremos que incluir los binarios de FFmpeg y modificar el programa para localizar esos ejecutables desde el directorio de la aplicación.
Limitaciones de esta versión
Aunque el programa resulta perfectamente válido como herramienta experimental y punto de partida, existen varios aspectos que pueden mejorarse.
No garantiza exactamente 10 MB
El cálculo del bitrate es aproximado. El tamaño real debe comprobarse después de la codificación.
No utiliza codificación en dos pasadas
El programa utiliza una única pasada de codificación.
Un sistema basado en two-pass encoding puede proporcionar un control más preciso de la distribución del bitrate cuando el objetivo principal es conseguir un tamaño determinado.
El bitrate mínimo puede impedir cumplir el límite
El código establece:
if bitrate_video < 100000:
bitrate_video = 100000
Esto evita utilizar valores extremadamente bajos, pero puede hacer imposible cumplir el límite de 10 MB en vídeos suficientemente largos.
El audio consume parte del presupuesto
Los 128 kbps del audio representan una cantidad fija de datos por segundo. En vídeos largos, ese flujo puede consumir una parte considerable del presupuesto disponible.
No existe reducción automática de resolución
Si un vídeo tiene una resolución muy elevada y una duración considerable, reducir únicamente el bitrate puede producir una calidad visual muy baja.
Una aplicación más inteligente podría reducir automáticamente la resolución cuando el bitrate disponible sea insuficiente.
La interfaz puede mejorarse en el manejo de hilos
La versión actual actualiza algunos widgets desde el hilo secundario. Para una aplicación de producción sería preferible utilizar una cola de comunicación y actualizar Tkinter exclusivamente desde el hilo principal.
¿Cómo podríamos mejorar el algoritmo?
Una versión avanzada podría utilizar una estrategia mucho más inteligente:
- Analizar duración, resolución, FPS y codecs.
- Calcular el bitrate disponible.
- Determinar si la resolución actual es viable.
- Reducir resolución si fuera necesario.
- Seleccionar automáticamente un codec adecuado.
- Realizar una primera estimación.
- Codificar.
- Medir el tamaño real.
- Recalcular el bitrate.
- Repetir hasta entrar dentro del límite.
El resultado sería un sistema mucho más cercano a un compresor adaptativo basado en presupuesto de bits.
Mejoras futuras
A partir de este proyecto se pueden implementar numerosas funciones adicionales:
- Selector de tamaño máximo.
- Presets de 5, 10, 25, 50 y 100 MB.
- Codificación H.264.
- Codificación H.265/HEVC.
- Codificación AV1.
- Two-pass encoding.
- Reintentos automáticos.
- Reducción automática de resolución.
- Selección automática de bitrate de audio.
- Cancelación de procesos.
- Arrastrar y soltar archivos.
- Procesamiento por lotes.
- Previsualización del vídeo.
- Estimación previa del tamaño.
- Historial de conversiones.
- Detección automática de FFmpeg.
- Distribución como aplicación portable.
Una posible arquitectura para una versión profesional
Si el proyecto creciera, sería recomendable separar la aplicación en diferentes capas:
┌─────────────────────────────────────┐ │ GUI / TKINTER │ ├─────────────────────────────────────┤ │ APPLICATION LAYER │ │ │ │ CompressionController │ │ ProgressManager │ │ JobManager │ ├─────────────────────────────────────┤ │ MEDIA ENGINE │ │ │ │ FFmpegRunner │ │ FFprobeAnalyzer │ │ BitrateCalculator │ │ SizeValidator │ ├─────────────────────────────────────┤ │ SYSTEM LAYER │ │ │ │ FFmpeg │ │ FFprobe │ └─────────────────────────────────────┘
De esta manera, la interfaz gráfica dejaría de depender directamente de los detalles internos de FFmpeg y sería mucho más sencillo sustituir componentes o añadir nuevos métodos de compresión.
Conclusión
Este proyecto demuestra cómo podemos construir una herramienta multimedia funcional utilizando Python como capa de control y FFmpeg como motor de procesamiento.
Python se encarga de la interfaz gráfica, selección de archivos, cálculo del bitrate, ejecución de procesos, seguimiento del progreso y validación del resultado, mientras que FFmpeg realiza la codificación audiovisual.
La idea fundamental puede resumirse en:
VÍDEO │ ▼ FFPROBE │ ▼ DURACIÓN │ ▼ PRESUPUESTO DE BITS │ ▼ BITRATE OBJETIVO │ ▼ FFMPEG │ ▼ ARCHIVO COMPRIMIDO │ ▼ COMPROBACIÓN DEL TAMAÑO │ ├──► ≤ 10 MB → ÉXITO │ └──► > 10 MB → AJUSTAR Y REPETIR
La versión original ya proporciona una base interesante para experimentar con FFmpeg, FFprobe, codificación de vídeo, cálculo de bitrate, subprocess, threading y desarrollo de interfaces gráficas en Python.
Pero el verdadero salto hacia una herramienta profesional estaría en convertir el cálculo inicial en un sistema adaptativo: medir el resultado real, ajustar automáticamente los parámetros y repetir el proceso hasta encontrar la mejor combinación posible entre tamaño, resolución, bitrate, codec y calidad visual.
Y ahí es donde este pequeño script deja de ser simplemente un “compresor de 10 MB” y empieza a convertirse en un auténtico motor de compresión audiovisual basado en presupuesto de bits.
Nota técnica final: si el requisito real es que el archivo nunca supere un límite estricto de 10 MB, no conviene confiar únicamente en una estimación inicial de bitrate. La estrategia correcta es dejar margen para el overhead, codificar, comprobar el tamaño real y, si es necesario, reajustar los parámetros y repetir la operación.
Visitas: 6
Automation & Data Specialist | Web Development | Data Processing & Integration
