O FFmpeg é o canivete suíço do processamento multimédia, capaz de transcodificar, fazer streaming, aplicar filtros e manipular praticamente qualquer formato de áudio/vídeo. Este guia aborda padrões práticos de utilização do FFmpeg na perspetiva de um programador sénior.
Porquê o FFmpeg
O FFmpeg está por detrás da maioria das plataformas de vídeo:
- Suporte Universal de Formatos: Lida com praticamente todos os codecs e contentores
- Filtros Poderosos: Redimensionar, recortar, sobrepor, corrigir a cor e muito mais
- Capacidade de Streaming: Saída RTMP, HLS, DASH
- Suporte de Legendas: Incorporar, extrair e renderizar legendas
- Processamento em Lote: Automatizar por script qualquer fluxo de trabalho multimédia
Instalação
# Ubuntu/Debian
sudo apt install ffmpeg
# CentOS/RHEL
sudo dnf install ffmpeg
# macOS
brew install ffmpeg
# Verificar a instalação
ffmpeg -version
Conceitos Básicos
Estrutura de Comando do FFmpeg
ffmpeg [global_options] [input_options] -i input [output_options] output
Contentor vs Codec
- Contentor: Formato de ficheiro (MP4, MKV, AVI)
- Codec de Vídeo: Compressão de vídeo (H.264, H.265, VP9)
- Codec de Áudio: Compressão de áudio (AAC, MP3, Opus)
Verificar informações do ficheiro:
ffprobe -v error -show_format -show_streams input.mp4
Tarefas Comuns de Transcodificação
Converter Entre Formatos
# MKV para MP4 (re-encode)
ffmpeg -i input.mkv -c:v libx264 -c:a aac output.mp4
# MKV para MP4 (copiar streams, sem re-encoding)
ffmpeg -i input.mkv -c copy output.mp4
# AVI para WebM
ffmpeg -i input.avi -c:v libvpx-vp9 -c:a libopus output.webm
Alterar a Qualidade de Vídeo
# Constant Rate Factor (CRF) — mais baixo = melhor qualidade
# H.264: 18-28 é um bom intervalo; 23 é o valor predefinido
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
# H.265 (HEVC) — melhor compressão
ffmpeg -i input.mp4 -c:v libx265 -crf 28 output.mp4
# Bitrate alvo
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M output.mp4
# Codificação em duas passagens (melhor qualidade para tamanho alvo)
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 1 -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 2 output.mp4
Redimensionar Vídeo
# Escalar para uma resolução específica
ffmpeg -i input.mp4 -vf "scale=1280:720" output.mp4
# Escalar mantendo a proporção
ffmpeg -i input.mp4 -vf "scale=1280:-1" output.mp4 # Altura automática
ffmpeg -i input.mp4 -vf "scale=-1:720" output.mp4 # Largura automática
# Escalar para caber dentro das dimensões (com padding, se necessário)
ffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4
Trabalhar com Legendas
Converter Legendas do YouTube para SRT
Formato VTT do YouTube para SRT:
ffmpeg -i subtitles.vtt subtitles.srt
Incorporar Legendas (Soft Subs)
Legendas como stream separado (pode ser ativado/desativado):
# Adicionar SRT como stream de legendas
ffmpeg -i video.mp4 -i subtitles.srt -c copy -c:s mov_text output.mp4
# Adicionar legendas VTT
ffmpeg -i video.mp4 -i subtitles.vtt -c copy -c:s webvtt output.mkv
# Múltiplas faixas de legendas
ffmpeg -i video.mp4 -i english.srt -i spanish.srt \
-c copy -c:s mov_text \
-metadata:s:s:0 language=eng \
-metadata:s:s:1 language=spa \
output.mp4
Queimar Legendas no Vídeo (Hard Subs)
Legendas renderizadas sobre o vídeo (permanente):
# Queimar legendas SRT
ffmpeg -i video.mp4 -vf "subtitles=subtitles.srt" output.mp4
# Personalizar o estilo das legendas
ffmpeg -i video.mp4 -vf "subtitles=subtitles.srt:force_style='FontSize=24,PrimaryColour=&H00FFFF&'" output.mp4
# Queimar legendas ASS/SSA (preserva o estilo)
ffmpeg -i video.mp4 -vf "ass=subtitles.ass" output.mp4
Extrair Legendas
# Extrair o primeiro stream de legendas
ffmpeg -i video.mkv -map 0:s:0 subtitles.srt
# Extrair todos os streams de legendas
ffmpeg -i video.mkv -map 0:s subtitles_%d.srt
Processamento de Áudio
Extrair Áudio
# Extrair como MP3
ffmpeg -i video.mp4 -vn -c:a libmp3lame -q:a 2 audio.mp3
# Extrair no formato original
ffmpeg -i video.mp4 -vn -c:a copy audio.aac
Alterar Áudio
# Alterar o codec de áudio
ffmpeg -i input.mp4 -c:v copy -c:a aac output.mp4
# Ajustar o volume
ffmpeg -i input.mp4 -filter:a "volume=1.5" output.mp4
# Normalizar o áudio
ffmpeg -i input.mp4 -filter:a loudnorm output.mp4
# Remover o áudio
ffmpeg -i input.mp4 -an output.mp4
Substituir Faixa de Áudio
ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 output.mp4
Cortar e Juntar
Cortar Segmentos de Vídeo
# Cortar a partir de 00:01:00 durante 30 segundos
ffmpeg -i input.mp4 -ss 00:01:00 -t 30 -c copy output.mp4
# Cortar de 00:01:00 a 00:02:30
ffmpeg -i input.mp4 -ss 00:01:00 -to 00:02:30 -c copy output.mp4
# Procura rápida (colocar -ss antes de -i para ficheiros grandes)
ffmpeg -ss 00:01:00 -i input.mp4 -t 30 -c copy output.mp4
Concatenar Vídeos
Criar lista de ficheiros videos.txt:
file 'video1.mp4'
file 'video2.mp4'
file 'video3.mp4'
Juntar ficheiros:
# Mesmo codec (sem re-encoding)
ffmpeg -f concat -safe 0 -i videos.txt -c copy output.mp4
# Codecs diferentes (re-encode)
ffmpeg -f concat -safe 0 -i videos.txt -c:v libx264 -c:a aac output.mp4
Filtros de Vídeo
Exemplos Comuns de Filtros
# Recortar vídeo (largura:altura:x:y)
ffmpeg -i input.mp4 -vf "crop=640:480:100:50" output.mp4
# Rodar vídeo
ffmpeg -i input.mp4 -vf "transpose=1" output.mp4 # 90° no sentido dos ponteiros do relógio
ffmpeg -i input.mp4 -vf "transpose=2" output.mp4 # 90° no sentido contrário ao dos ponteiros do relógio
ffmpeg -i input.mp4 -vf "hflip" output.mp4 # Inversão horizontal
ffmpeg -i input.mp4 -vf "vflip" output.mp4 # Inversão vertical
# Acelerar/abrandar
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -af "atempo=2.0" output.mp4 # Velocidade 2x
ffmpeg -i input.mp4 -vf "setpts=2.0*PTS" -af "atempo=0.5" output.mp4 # Velocidade 0,5x
# Adicionar fade in/out
ffmpeg -i input.mp4 -vf "fade=t=in:st=0:d=2,fade=t=out:st=58:d=2" output.mp4
Adicionar Marca de Água/Sobreposição
# Marca de água de imagem no canto
ffmpeg -i video.mp4 -i watermark.png \
-filter_complex "overlay=W-w-10:H-h-10" \
output.mp4
# Sobreposição de texto
ffmpeg -i video.mp4 \
-vf "drawtext=text='Copyright 2024':fontsize=24:fontcolor=white:x=10:y=H-th-10" \
output.mp4
# Carimbo temporal
ffmpeg -i video.mp4 \
-vf "drawtext=text='%{pts\:hms}':fontsize=24:fontcolor=white:x=10:y=10" \
output.mp4
Criar Miniaturas e GIFs
Extrair Miniaturas
# Frame único num instante específico
ffmpeg -i video.mp4 -ss 00:00:10 -vframes 1 thumbnail.jpg
# Múltiplas miniaturas (a cada 10 segundos)
ffmpeg -i video.mp4 -vf "fps=1/10" thumbnail_%04d.jpg
# Grelha/sprite de miniaturas
ffmpeg -i video.mp4 -vf "fps=1/5,scale=160:-1,tile=5x5" sprite.jpg
Criar GIF
# GIF básico (ficheiro grande)
ffmpeg -i video.mp4 -t 5 output.gif
# GIF otimizado com paleta
ffmpeg -i video.mp4 -t 5 -vf "fps=15,scale=480:-1:flags=lanczos,palettegen" palette.png
ffmpeg -i video.mp4 -i palette.png -t 5 -filter_complex "fps=15,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
Streaming
Gerar HLS para Streaming Adaptativo
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-hls_time 10 \
-hls_list_size 0 \
-hls_segment_filename "segment_%03d.ts" \
playlist.m3u8
HLS com Múltiplas Qualidades
ffmpeg -i input.mp4 \
-filter_complex "[0:v]split=3[v1][v2][v3]; \
[v1]scale=1920:1080[v1out]; \
[v2]scale=1280:720[v2out]; \
[v3]scale=854:480[v3out]" \
-map "[v1out]" -map 0:a -c:v:0 libx264 -b:v:0 5M -c:a aac -b:a:0 192k \
-hls_time 10 -hls_playlist_type vod 1080p.m3u8 \
-map "[v2out]" -map 0:a -c:v:1 libx264 -b:v:1 2.5M -c:a aac -b:a:1 128k \
-hls_time 10 -hls_playlist_type vod 720p.m3u8 \
-map "[v3out]" -map 0:a -c:v:2 libx264 -b:v:2 1M -c:a aac -b:a:2 96k \
-hls_time 10 -hls_playlist_type vod 480p.m3u8
Processamento em Lote com Scripts
Exemplo de Script Bash
#!/bin/bash
INPUT_DIR="./raw"
OUTPUT_DIR="./processed"
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file" .mp4)
echo "Processing: $filename"
ffmpeg -i "$file" \
-c:v libx264 -crf 23 \
-c:a aac -b:a 128k \
-vf "scale=1280:-1" \
"$OUTPUT_DIR/${filename}_720p.mp4"
done
echo "Done!"
Integração com Node.js
const { spawn } = require('child_process');
function transcodeVideo(input, output, options = {}) {
return new Promise((resolve, reject) => {
const args = [
'-i', input,
'-c:v', 'libx264',
'-crf', options.crf || '23',
'-c:a', 'aac',
'-y', // Substituir saída
output
];
const ffmpeg = spawn('ffmpeg', args);
ffmpeg.stderr.on('data', (data) => {
console.log(`FFmpeg: ${data}`);
});
ffmpeg.on('close', (code) => {
if (code === 0) {
resolve(output);
} else {
reject(new Error(`FFmpeg exited with code ${code}`));
}
});
});
}
// Utilização
transcodeVideo('input.mp4', 'output.mp4', { crf: '28' })
.then(output => console.log('Created:', output))
.catch(err => console.error('Error:', err));
Principais Conclusões
- Use
-c copy quando possível: Evite re-encoding para ganhar velocidade - CRF para controlo de qualidade: Valores mais baixos = maior qualidade
- Duas passagens para tamanho alvo: Melhor qualidade a um bitrate específico
- Paleta para GIFs: Essencial para boa qualidade
-ss antes de -i: Procura mais rápida em ficheiros grandes- Teste em clipes curtos: Prototipe filtros antes de renderizações completas
A profundidade do FFmpeg é enorme — estes padrões cobrem a maioria das necessidades comuns, mas a documentação revela inúmeras outras capacidades para fluxos de trabalho especializados.