Batch Processing com FFmpeg
Processar um arquivo é simples. Processar 50 arquivos ao mesmo tempo, com a mesma configuração, sem tocar em cada um, é onde o FFmpeg realmente brilha.
Loop simples no terminal
# Converte todos os .mov para .mp4 na pasta atual:for f in *.mov; do ffmpeg -i "$f" -c:v libx264 -crf 18 -pix_fmt yuv420p "${f%.mov}.mp4"done
# Redimensiona todos os MP4 para 1080pfor f in *.mp4; do ffmpeg -i "$f" -vf "scale=1920:1080" -c:v libx264 -crf 18 "1080p_${f}"done
# Gera previews de baixa qualidade de renders pesadosfor f in *.mov; do ffmpeg -i "$f" -c:v libx264 -crf 28 -vf "scale=640:-2" -preset ultrafast "preview_${f%.mov}.mp4"doneGet-ChildItem *.mov | ForEach-Object { $output = $_.BaseName + '.mp4' ffmpeg -i $_.Name -c:v libx264 -crf 18 -pix_fmt yuv420p $output}Script Python para batch com mais controle
import subprocessimport osimport globfrom pathlib import Path
def convert_to_mp4(input_dir, output_dir, crf=18): Path(output_dir).mkdir(parents=True, exist_ok=True) files = glob.glob(os.path.join(input_dir, '*.mov')) print(f"Encontrados {len(files)} arquivos.")
for i, f in enumerate(sorted(files), 1): name = Path(f).stem output = os.path.join(output_dir, f"{name}.mp4")
cmd = [ 'ffmpeg', '-i', f, '-c:v', 'libx264', '-crf', str(crf), '-preset', 'slow', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-b:a', '192k', '-movflags', '+faststart', output ]
print(f"[{i}/{len(files)}] {name}") result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0: print(f" ERRO: {result.stderr[-200:]}") else: orig = os.path.getsize(f) / (1024*1024) out = os.path.getsize(output) / (1024*1024) print(f" OK: {orig:.1f}MB -> {out:.1f}MB")
convert_to_mp4('/renders/master_files', '/renders/web_delivery')Sequências de render para vídeo
import subprocess, glob, re, osfrom pathlib import Path
def sequence_to_video(frames_dir, output_file, fps=24): files = sorted(glob.glob(os.path.join(frames_dir, '*.png'))) if not files: files = sorted(glob.glob(os.path.join(frames_dir, '*.jpg')))
print(f"Encontrados {len(files)} frames.")
# Detecta padrão de numeração first = os.path.basename(files[0]) match = re.search(r'(\d+)', first) num_digits = len(match.group(1)) prefix = first[:match.start()] ext = os.path.splitext(first)[1] pattern = os.path.join(frames_dir, f"{prefix}%0{num_digits}d{ext}")
subprocess.run([ 'ffmpeg', '-framerate', str(fps), '-i', pattern, '-c:v', 'libx264', '-crf', '18', '-pix_fmt', 'yuv420p', output_file ], check=True) print(f"Vídeo criado: {output_file}")
sequence_to_video('/renders/my_animation', '/renders/my_animation.mp4')Processamento paralelo
# Mac/Linux: processa 4 ao mesmo tempo com xargsls *.mov | xargs -P 4 -I{} bash -c 'ffmpeg -i "{}" -c:v libx264 -crf 18 "{}.mp4"'# Python com multiprocessingimport subprocessimport globfrom concurrent.futures import ProcessPoolExecutor
def converter(arquivo): saida = arquivo.replace('.mov', '.mp4') subprocess.run(['ffmpeg', '-i', arquivo, '-c:v', 'libx264', '-crf', '18', saida]) return saida
arquivos = glob.glob('*.mov')with ProcessPoolExecutor(max_workers=4) as executor: resultados = list(executor.map(converter, arquivos))Verificando resultado em batch
import subprocess, json, glob, os
def check_videos(folder): for video in sorted(glob.glob(os.path.join(folder, '*.mp4'))): cmd = ['ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_streams', '-show_format', video] data = json.loads(subprocess.run(cmd, capture_output=True, text=True).stdout)
vs = next(s for s in data['streams'] if s['codec_type'] == 'video') dur = float(data['format']['duration'])
print(f"{os.path.basename(video):40} | " f"{vs['width']}x{vs['height']} | " f"{vs['codec_name']:6} | {dur:.1f}s")Tip
Comando útil antes de rodar batch: ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1 arquivo.mp4 verifica se o arquivo está íntegro sem ter que abrir.