Optimización de FFMPEG al volver a codificar un archivo mkv a mp4 con subtítulos incrustados.
He escrito un programa con python, ffmpeg y la terminal de Linux.
Funciona, pero es muy lento…
Y quiero optimizar mi código, pero no sé qué podría hacer para hacerlo.
Mi código:
“`
import os
def extractSub():
"""
Esta función extrae los subtítulos de archivos mkv y los coloca en la carpeta mp4Folder.
"""
dirLocate = "./mkvFolder/"
for filename in os.listdir(dirLocate):
if(filename.endswith(".mkv")):
os.system("ffmpeg -i {0} -map 0:s:0 {0}.ass".format(dirLocate + filename))
def burnSub():
"""
Esta función quema/hardsub los subtítulos extraídos con la función extractSub() y los coloca en el archivo mp4 final.
"""
dirLocate = "./mkvFolder/"
mp4Locate = "./mp4Folder/"
for filename in os.listdir(dirLocate):
if(filename.endswith(".mkv")):
os.system("ffmpeg -i {0} subtitles={0} {1}.mp4".format(dirLocate + filename, mp4Locate + filename[0:-4]))
start = time.time()
extractSub()
burnSub()
print("El tiempo utilizado para ejecutar esto se muestra a continuación")
end = time.time()“`
Espero haber dado suficientes detalles…
davy.ai
Código posible optimizado:
Explicaciones y mejoras:
El código original define dos funciones separadas, una para extraer los subtítulos y otra para quemarlos en los archivos .mp4. Sin embargo, ambas operaciones siempre se realizan juntas, en el mismo bucle que itera sobre los archivos en el directorio mkvFolder. Por lo tanto, es más eficiente combinarlas en una sola función. Esto también evita la redundancia de E/S de archivos y reduce la duplicación de código.
El código original utiliza la función
os.system()
para ejecutar comandos de FFmpeg. Si bien esto funciona, no es recomendable porque implica lanzar un nuevo proceso de shell para cada comando, lo que puede ser lento y poco seguro. Es mejor utilizar una biblioteca de Python comosubprocess
, que permite un mayor control y flexibilidad sobre la gestión de procesos. En este caso, como los comandos son simples y no requieren interacción, podemos utilizar la funciónsubprocess.run()
, que es un envoltorio de alto nivel alrededor dePopen()
.El código original no maneja errores ni verifica los códigos de retorno de los comandos de FFmpeg. Esto puede provocar fallos silenciosos o resultados inesperados si faltan los archivos de entrada, los directorios de salida no tienen permisos de escritura o las versiones/opciones de FFmpeg no son compatibles. Para evitar esto, podemos agregar comprobación de errores y registro al código. Por ejemplo, podemos usar la opción
-y
en los comandos de FFmpeg para sobrescribir los archivos de salida existentes sin preguntar, y podemos usar la excepciónsubprocess.CalledProcessError
para capturar cualquier código de retorno distinto de cero e imprimir un mensaje de error.El código original utiliza la concatenación de cadenas (+) para construir los nombres de archivo de entrada y salida a partir de las cadenas de directorio y extensión. Si bien esto funciona, puede provocar errores y vulnerabilidad a ataques de inyección si los nombres de archivo de entrada contienen caracteres especiales o espacios en blanco. Para evitar esto, podemos utilizar la función
os.path.join()
para concatenar de forma segura los componentes de la ruta, y podemos utilizar la notación de corte[:-4]
para eliminar la extensión ‘.mkv’ del nombre de archivo y reemplazarla por ‘.ass’ o ‘.mp4’.El código original no mide ni informa adecuadamente el tiempo de ejecución. Para solucionarlo, podemos utilizar la función
time.monotonic()
para medir el tiempo transcurrido de manera más precisa y fiable que la funcióntime.time()
(que puede verse afectada por la desviación del reloj o los cambios del sistema). También podemos formatear el mensaje de salida para incluir el tiempo de ejecución en segundos con dos decimales, lo cual es más legible e informativo que una marca de tiempo simple.